Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

15R4 Support (0876) #41

Closed
xenatisch opened this issue Jul 4, 2018 · 49 comments
Closed

15R4 Support (0876) #41

xenatisch opened this issue Jul 4, 2018 · 49 comments

Comments

@xenatisch
Copy link
Contributor

xenatisch commented Jul 4, 2018

Issue

The application does not support the FX interface for Alienware 15 R4.

Installed dependencies

  • libusb1.0
  • libcairo2-dev
  • python3.6.5 Anaconda
  • python-gi and python-gi-cairo
    and all other Python dependencies.

1. Expected behavior:

Recognise the AlienFX.

2. Actual behavior:

Throws the following error:

ERROR:root:No supported Alien FX controllers found!

3. Steps to reproduce the problem:

Run the application on Ubuntu 18.04 installed on an Alienware 15 R4 machine.

4. Specifications like the version of the project, install method, operating system, and hardware.

  • Project Version: Latest - cloned from the repository.
  • Operating System: Ubuntu 18.04 LTS x86_64
  • Hardware Version:
    • Host: Alienware 15 R4 1.1.6
    • Kernel: Kernel: 4.15.0-23-generic
    • Shell: bash 4.4.19
    • DE: GNOME 3.28.1
    • CPU: Intel i9-8950HK (12) @ 4.800GHz
    • GPU: NVIDIA GeForce GTX 1070 Mobile
    • Memory: 32026MiB

General info:

description: Notebook
product: Alienware 15 R4 (0876)
vendor: Alienware
version: 1.1.6
serial: ...
width: 64 bits
capabilities: smbios-3.1 dmi-3.1 smp vsyscall32
configuration: boot=normal chassis=notebook family=Alienware sku=0876 uuid=...
  *-core
       description: Motherboard
       product: Alienware 15 R4
       vendor: Alienware
       physical id: 0
       version: A00
       serial: ...
       slot: *
     *-firmware
          description: BIOS
          vendor: Alienware
          physical id: 0
          version: 1.1.6
          date: 05/22/2018
          size: 64KiB
          capacity: 15MiB
          capabilities: pci pnp upgrade shadowing cdboot bootselect edd int13floppy1200 int13floppy720 int13floppy2880 int5printscreen int9keyboard int14serial int17printer int10video acpi usb smartbattery biosbootspecification netboot uefi

FX interface:

*-usb:0 UNCLAIMED
   description: Human interface device
   product: AW-ELC
   vendor: Alienware
   physical id: 4
   bus info: usb@1:4
   version: 2.00
   serial: 00.01
   capabilities: usb-2.00
   configuration: speed=12Mbit/s

Please let me know if you need any additional info.

@derco0n
Copy link
Contributor

derco0n commented Jul 27, 2018

Please try newest version and test if zonescanning might help you creating your own definition.

If you could create a controller for your device, i bet a pull request would be appreciated.

@trackmastersteve trackmastersteve changed the title Support for Alienware 15 R4 (0876) 15R4 Support (0876) Jul 28, 2018
@axsaucedo
Copy link

This would be really useful for me as well. @derco0n if it helps, user @Gurjot95 commented in another github issue for the alienware 15 R4 with the following:

The new models since 13R3 needs 12 byte instruction to send to HID instead of the original 9. I have made the SDK which supports all alienware laptops. You can take it as reference.

https://github.com/Gurjot95/AlienFX-SDK/tree/master/AlienFX_SDK

@derco0n
Copy link
Contributor

derco0n commented Nov 20, 2018

This would be really useful for me as well. @derco0n if it helps, user @Gurjot95 commented in another github issue for the alienware 15 R4 with the following:

The new models since 13R3 needs 12 byte instruction to send to HID instead of the original 9. I have made the SDK which supports all alienware laptops. You can take it as reference.
https://github.com/Gurjot95/AlienFX-SDK/tree/master/AlienFX_SDK

I have an 17R3 and experienced the same issue (12 vs 9 Bytes).
I created a new controller.py. pull request was merged months ago.

Please sync to latest version and try to build a controller for your device using the zonescanner functionality.

@axsaucedo
Copy link

Thank you @derco0n. I tried running zonescanner for everything, but wasn't successful. I may have done something wrong, as it seems to get stuck every time it just says "Testing zone X". When I send CTRL-C, it sensibly says ERROR:root:Error while testing current zone... and then asks is anything blinking now? (y/n):, but the answer is no. This repeats throughout all the zones. I waited up to 5 minutes for one, so unless it would take longer to test each?

If it helps, this is the message that appears when I run sudo alienfx:

You are running alienfx under Python-Version: 2.7.15rc1 (default, Nov 12 2018, 14:31:15)
[GCC 7.3.0]
ERROR:root:No Alien FX controller, defined by a supported model, found!
would you like to perform a zonescan? (y/n):y
Performing zonescan...
Welcome. This will help you to scan for alienfx-controllers and their lightning zones.
Found device "0x187c / 0x0550". - Testing zones...
Testing zone "0x0001"

Thank you.

@derco0n
Copy link
Contributor

derco0n commented Nov 21, 2018 via email

@AbsyntheSyne
Copy link

I'm also having this issue. I also have an Alienware 15 R4 and it does the same exact thing. I can try to help if given instructions on what to do.

@DenDeze
Copy link

DenDeze commented Dec 10, 2018

same here (CTRL+C)

@DenDeze
Copy link

DenDeze commented Dec 10, 2018

Bus 001 Device 002: ID 187c:0550 Alienware Corporation
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 0 (Defined at Interface level)
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 64
idVendor 0x187c Alienware Corporation
idProduct 0x0550
bcdDevice 2.00
iManufacturer 1 Alienware
iProduct 2 AW-ELC
iSerial 3 00.01
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 41
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xe0
Self Powered
Remote Wakeup
MaxPower 0mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 3 Human Interface Device
bInterfaceSubClass 0 No Subclass
bInterfaceProtocol 0 None
iInterface 0
HID Device Descriptor:
bLength 9
bDescriptorType 33
bcdHID 1.11
bCountryCode 0 Not supported
bNumDescriptors 1
bDescriptorType 34 Report
wDescriptorLength 25
Report Descriptors:
** UNAVAILABLE **
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0021 1x 33 bytes
bInterval 10
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x01 EP 1 OUT
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0021 1x 33 bytes
bInterval 100
Device Status: 0x0001
Self Powered

@axsaucedo
Copy link

I have done some debugging and found more light on this issue.

It seems that the reason why it gets stuck every time it says Testing zone X is because the format required for the packet is actually not correct, or at least that is what it seems.

The class zonescanner had functions that appended arrays of the format pkt = [0x02, cls.CMD_XXXX, 0, 0, 0, 0, 0, 0, 0]. However it was producing an error, as it seems that the required packed size is longer, and started working when I changed it to pkt = [0x02, cls.CMD_SET_SPEED, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], which basically adds a padding of 3 extra bits.

I am still not 100% sure if this fixes the issue to a point where a proper zone-scan can be carried out, but it seems there may need to be modifications for a proper zone scan to be carried out.

I have made available the changes I made through this branch in a fork https://github.com/axsauze/alienfx/tree/alienware_15_r4_fix.

You can see the diff here PR https://github.com/trackmastersteve/alienfx/compare/master...axsauze:alienware_15_r4_fix?expand=1

A question for some of the core contributors (@derco0n, @trackmastersteve + @xenatisch), what do you think this may be due to, am I missing something or does the 15r4 has different hardware requirements for package files? If so happy to perform a zone search, but I need to understand a bit more of when it is working so the zonesearch can be carried out efficiently.

@DenDeze
Copy link

DenDeze commented Dec 28, 2018

@axsauze still not working

@derco0n
Copy link
Contributor

derco0n commented Jan 5, 2019

i just got my fingers on a 17R5 which uses the same controller.

Working on a solution.
Please be patient.

@DenDeze
Copy link

DenDeze commented Jan 14, 2019

@derco0n i hope you will get things working!

@kmescher
Copy link

kmescher commented Feb 8, 2019

I'm not sure how far @derco0n has gotten at the moment, but I can tell you that the newer controller (0x0550) has a completely new protocol. The packet length is 33 bytes, and it requires multiple packets for many of the operations.

For example, if you send the following two packets (hex):
032002000000000000000000000000000000000000000000000000000000000000
032664000d0001020405060708090a0b0c0d000000000000000000000000000000

That will cause all the lights to go out (except the macro keys and power button)

It appears that the command structure goes a bit like this:
03 (API version maybe?)
Command Code (0x26 on the second line)
Parameters

For the second line, the 0x64 is the light intensity, but it's backwards, as 0x64 refers to 0d100. Setting the intensity byte back to 0x00 will turn the lights back on. Maybe is a %Dimming value.

The 0x0d is referring to the number of zones that will be affected (14).

The zones are as follows (all in hex):
00 - Alien Head
01 - Logo just under the screen
02 - Touchpad
03 - Power button (note that it's not in the command above)
04 - Keyboard Numeric Pad (Standard keyboard here)
05 - Keyboard Right
06 - Keyboard Center
07 - Keyboard Left
08 - Chassis Left Stripe
09 - Chassis Right Stripe
0A - Lid Left Stripe
0B - Lid Right Stripe
0C, 0D - No idea

We 'can' write the packets using hidapi (which is way easier), but for some stupid reason, none of the hid drivers (or hidapi itself, or the hidraw device) can issue a GET_REPORT control request to request an input report. So we can't read the status back. I have half a mind to rebuild hidapi against libusb myself and add that code. Sigh...Maybe I'll just write a kernel driver off of the hid core which CAN.

Here's my (terrible) python3 code to send the two messages above:
import hidapi

device=hidapi.Device(vendor_id=0x187c, product_id=0x0550)
godark_string1='032002000000000000000000000000000000000000000000000000000000000000'
godark_string2='032664000d0001020405060708090a0b0c0d000000000000000000000000000000'
report_id=b'\x00'
device.write(bytearray.fromhex(godark_string1),report_id)
#answer=device.read()
device.write(bytearray.fromhex(godark_string2),report_id)
device.close()

Much easier than messing with raw usb messages.

I've captured packet dumps of most of the operations available in AWCC with one exception (RainbowWave on the Keyboard), and I only have the standard keyboard, so my protocol analysis is slightly incomplete. I can send what I know if anyone's interested.

@DenDeze
Copy link

DenDeze commented Feb 18, 2019

Good job!!!

for the user who cannot get this script to work:

sudo apt install python3-hidapi
nano alienfx.py (copy code made by @kmescher)

#/usr/bin/python3
import sys
import hidapi
if len(sys.argv) > 1:
        device=hidapi.Device(vendor_id=0x187c, product_id=0x0550)
        godark_string1='032002000000000000000000000000000000000000000000000000000000000000'
        godark_string2='0326' + sys.argv[1] + '000d0001020405060708090a0b0c0d000000000000000000000000000000'
        report_id=b'\x00'
        device.write(bytearray.fromhex(godark_string1),report_id)
        device.write(bytearray.fromhex(godark_string2),report_id)
        device.close()
else:
        print('use a number between 00 and 64')


sudo chmod 775 alienfx.py
sudo python3 alienfx.py

DONE your leds are off...

@axsaucedo
Copy link

Thank you @kmescher and @DenDeze. I have tried running the command you provide @DenDeze but unfortunately I am getting the following exception:

Traceback (most recent call last):
  File "godark.py", line 3, in <module>
    device=hidapi.Device(vendor_id=0x187c, product_id=0x0550)
  File "/usr/lib/python3/dist-packages/hidapi.py", line 154, in __init__
    serial_number)
TypeError: initializer for ctype 'wchar_t *' must be a cdata pointer, not NoneType
Exception ignored in: <bound method Device.__del__ of <hidapi.Device object at 0x7f1ba64fc588>>
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/hidapi.py", line 164, in __del__
    if self._device is not None:
AttributeError: 'Device' object has no attribute '_device'

When I run the python3 prompt, it fails when running the first line:

>>> hidapi.Device(vendor_id=0x187c, product_id=0x0550)                                                   
Exception ignored in: <bound method Device.__del__ of <hidapi.Device object at 0x7fdb0214ecc0>>          
Traceback (most recent call last):                                                                       
  File "/usr/lib/python3/dist-packages/hidapi.py", line 164, in __del__                                  
    if self._device is not None:                                                                         
AttributeError: 'Device' object has no attribute '_device'                                               
Traceback (most recent call last):                                                                       
  File "<stdin>", line 1, in <module>                                                                    
  File "/usr/lib/python3/dist-packages/hidapi.py", line 154, in __init__                                 
    serial_number)                                                                                       
TypeError: initializer for ctype 'wchar_t *' must be a cdata pointer, not NoneType

I am using Python 3.6.7 with the following details:

Python 3.6.7 (default, Oct 22 2018, 11:32:17)                                                            
[GCC 8.2.0] on linux                                                                          

Is there a requirement on the version of Python for hidapi to work correctly? What version of Python are you running?

Thanks.

@DenDeze
Copy link

DenDeze commented Feb 18, 2019

Thank you @kmescher and @DenDeze. I have tried running the command you provide @DenDeze but unfortunately I am getting the following exception:

Traceback (most recent call last):
  File "godark.py", line 3, in <module>
    device=hidapi.Device(vendor_id=0x187c, product_id=0x0550)
  File "/usr/lib/python3/dist-packages/hidapi.py", line 154, in __init__
    serial_number)
TypeError: initializer for ctype 'wchar_t *' must be a cdata pointer, not NoneType
Exception ignored in: <bound method Device.__del__ of <hidapi.Device object at 0x7f1ba64fc588>>
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/hidapi.py", line 164, in __del__
    if self._device is not None:
AttributeError: 'Device' object has no attribute '_device'

When I run the python3 prompt, it fails when running the first line:

>>> hidapi.Device(vendor_id=0x187c, product_id=0x0550)                                                   
Exception ignored in: <bound method Device.__del__ of <hidapi.Device object at 0x7fdb0214ecc0>>          
Traceback (most recent call last):                                                                       
  File "/usr/lib/python3/dist-packages/hidapi.py", line 164, in __del__                                  
    if self._device is not None:                                                                         
AttributeError: 'Device' object has no attribute '_device'                                               
Traceback (most recent call last):                                                                       
  File "<stdin>", line 1, in <module>                                                                    
  File "/usr/lib/python3/dist-packages/hidapi.py", line 154, in __init__                                 
    serial_number)                                                                                       
TypeError: initializer for ctype 'wchar_t *' must be a cdata pointer, not NoneType

I am using Python 3.6.7 with the following details:

Python 3.6.7 (default, Oct 22 2018, 11:32:17)                                                            
[GCC 8.2.0] on linux                                                                          

Is there a requirement on the version of Python for hidapi to work correctly? What version of Python are you running?

Thanks.
Python 3.7.2+ (default, Feb 2 2019, 14:31:48)
[GCC 8.2.0] on linux
try updating python and else:

try running sudo apt-get install python-dev libusb-1.0-0-dev libudev-dev (please report back if this works then i update my post)

also i updated my script so can use it as sudo python3 alienfx.py (00-64)

@axsaucedo
Copy link

I've ran sudo apt-get install python-dev libusb-1.0-0-dev libudev-dev but unfortunately I am still getting the same error.

I have also tried installing the packages listed in the "hidapi package in Ubuntu" here https://launchpad.net/ubuntu/+source/hidapi

Finally I tried installing cython3 using sudo apt install cython3.

I am still getting the same error. It does seem to be an issue building the bindings with the C/C++ library.

Have you seen this issue before? Perhaps I could try building hidapi from source. Alternatively, it seems that you are using Python 3.7.2, would that perhaps be a dependency of minimum Python version for HIDAPI?

Thanks.

@DenDeze
Copy link

DenDeze commented Feb 18, 2019

l will update my script with dim levels and zones, again thank you @kmescher for the exampel code.

@DenDeze
Copy link

DenDeze commented Feb 18, 2019

I've ran sudo apt-get install python-dev libusb-1.0-0-dev libudev-dev but unfortunately I am still getting the same error.

I have also tried installing the packages listed in the "hidapi package in Ubuntu" here https://launchpad.net/ubuntu/+source/hidapi

Finally I tried installing cython3 using sudo apt install cython3.

I am still getting the same error. It does seem to be an issue building the bindings with the C/C++ library.

Have you seen this issue before? Perhaps I could try building hidapi from source. Alternatively, it seems that you are using Python 3.7.2, would that perhaps be a dependency of minimum Python version for HIDAPI?

Thanks.

else try this:
sudo pip install --upgrade setuptools
sudo pip install hidapi

i hope it works

@axsaucedo
Copy link

I had a look at the hidapi.py file, and it seems that the signature for the cython function required to initialise the device connection is hid_device *(*)(unsigned short, unsigned short, wchar_t *), which means that the error is because the function expects a string for the third parameter (serial_number), and it's receiving None.

I tried calling it by adding my serial_number as device=hidapi.Device(vendor_id=0x187c, product_id=0x0550, serial_number="MY_SERIAL_NUMBER").

The call is now providing the following traceback:

Traceback (most recent call last):
  File "godark.py", line 3, in <module>
    device=hidapi.Device(vendor_id=0x187c, product_id=0x0550, serial_number="78VB84UHK5SP")
  File "/usr/lib/python3/dist-packages/hidapi.py", line 159, in __init__
    raise IOError("Could not open connection to device.")
OSError: Could not open connection to device.

Unfortunately it seems that for some reason my hidapi is not able to get access to the device. I also tried running it with Python 3.7.2 but unfortunately the same error appeared. I also tried updating setuptools and installing hidapi.

For context, the code on hidapi.Device is the following:

class Device(object):
    def __init__(self, info=None, path=None, vendor_id=None, product_id=None,
                 serial_number=None, blocking=True):
        """ Open a connection to a HID device.
        This can be done either from a DeviceInfo object, a device path or
        a combination of vendor id, product id and an optional serial number.
        If no serial number is passed, the first matching device will be
        selected.
        By setting :param blocking: to True, all reads will be blocking by
        default, otherwise they will return `None` if no data is available.

        :param info:        Information about the device to initialize
        :type info:         DeviceInfo
        :param path:        Platform-specific path to the device (e.g.
                            `/dev/hidraw0` on Linux)
        :type path:         str
        :param vendor_id:   Vendor ID
        :type vendor_id:    int
        :param product_id:  Product ID
        :type product_id:   int
        :param serial_number: Device serial number
        :type serial_number: str
        :param blocking:    Enable blocking reads by default
        :type blocking:     boolean

        """
        if info is not None:
            self._device = hidapi.hid_open_path(info.path)
        elif path is not None:
            self._device = hidapi.hid_open_path(path)
        elif not (vendor_id is None or product_id is None):
            self._device = hidapi.hid_open(vendor_id, product_id,serial_number)
        else:
            raise ValueError("Must provide either a DeviceInfo object, 'path' "
                             "or 'vendor_id' and 'product_id'.")
        if self._device == ffi.NULL:
            raise IOError("Could not open connection to device.")
        if not blocking:
            hidapi.hid_set_nonblocking(self._device, 1)
...

Please let me know if you have any ideas on how this could be addressed. Otherwise I will update if I find a walk-around.

@DenDeze
Copy link

DenDeze commented Feb 18, 2019

""" Open a connection to a HID device.
        This can be done either from a DeviceInfo object, a device path or
        a combination of vendor id, product id and an optional serial number.
        If no serial number is passed, the first matching device will be
        selected.

Open a connection to a HID device.
This can be done either from a DeviceInfo object, a device path or
a combination of vendor id, product id and an optional serial number.
If no serial number is passed, the first matching device will be
selected.

It either seems like your device is just not found / with or without serial...

what does:
lsusb | grep Alien
shows you?

@axsaucedo
Copy link

@DenDeze thanks for the docstring, seems the device is indeed not found. I actually searched for the serial number based on my service tag and tried to add it manually as a string, but indeed it still didn't find the device.

When running that command I get Bus 001 Device 002: ID 187c:0550 Alienware Corporation which seems to be the vendor ID and product ID. Is the serial number also supposed to appear here?

@DenDeze
Copy link

DenDeze commented Feb 19, 2019

@axsauze the line that is shown is correct, your usb device is indeed found so the problem is not in your hardware. Do you run the python scripts with sudo? i get the exact same error when not running the commands with sudo...

Serial is not shown with lsusb.

please run commands with sudo and dump a complete shell output please.

@DenDeze
Copy link

DenDeze commented Feb 19, 2019

@axsauze the line that is shown is correct, your usb device is indeed found so the problem is not in your hardware. Do you run the python scripts with sudo? Serial is not shown with lsusb. Maybe your python is not working correct. Are there usb packages installed true pip and your package manager?

you can actualy run the same code with python2
just install python-hidapi:

sudo apt install python-hidapi

make new file:

sudo nano alienfxp2.py

copy in alienfxp2.py:

#/usr/bin/python
import sys
import hidapi
if len(sys.argv) > 1:
        device=hidapi.Device(vendor_id=0x187c, product_id=0x0550)
        godark_string1='032002000000000000000000000000000000000000000000000000000000000000'
        godark_string2='0326' + sys.argv[1] + '000d0001020405060708090a0b0c0d000000000000000000000000000000'
        report_id=b'\x00'
        device.write(bytearray.fromhex(godark_string1),report_id)
        device.write(bytearray.fromhex(godark_string2),report_id)
        device.close()
else:
        print('use a number between 00 and 64')

make the file executable:

sudo chmod 775 alienfxp2.py

run like:

sudo python2 alienfxp2.py 64
sudo python2 alienfxp2.py 00

@DenDeze
Copy link

DenDeze commented Feb 19, 2019

@kmescher can you provide more codes please?

@kmescher
Copy link

kmescher commented Feb 20, 2019

TL;DR: I completed a much more comprehensive look at how the new communication works after I did my first post. This will be a VERY long post. You have been warned.

Since the replies coming back from the controller are sometimes interesting, you may not want to use hidapi (since it doesn't send the GET_REPORT control transfer; neither does hidraw, and hiddev is a pain; Grr......). Thankfully, you can repeat the same idea with the following code using python and libusb (I saved as hidreport.py)

import usb
def hid_set_output_report(dev, report, report_id=0):
""" Implements HID SetReport via USB control transfer """
dev.ctrl_transfer(
0x21, # REQUEST_TYPE_CLASS | RECIPIENT_INTERFACE | ENDPOINT_OUT
9, # SET_REPORT
0x200+report_id, 0x00,
report)

def hid_get_input_report(dev,length,report_id=0):
""" Implements HID GetReport via USB control transfer """
return dev.ctrl_transfer(
0xA1, # REQUEST_TYPE_CLASS | RECIPIENT_INTERFACE | ENDPOINT_IN
1, # GET_REPORT
0x100+report_id, 0x00,
length)

Then here's my stupid test code:

#!/usr/bin/python3
import usb
from hidreport import *
import binascii

device=usb.core.find(idVendor=0x187c, idProduct=0x0550)
while (1):
string=input("Type the command string\n")
bytes=bytearray.fromhex(string)
bytes+=bytearray.fromhex('00' * (33-len(bytes)))
print("Out %s\n" % (bytes))
hid_set_output_report(device, bytes)
print("In%s\n" % (binascii.hexlify(hid_get_input_report(device, 33))))
input("Press enter to continue")

Much easier.... you type the command you want, it automatically pads it, then prints out the reply.

Also to avoid a ton of dmesg output when working w/ libusb, you need to keep the HID driver from capturing this device. Put this into /etc/modprobe.d/ignore-awelc.conf (as root):

options usbhid quirks=0x187c:0x0550:0x0004

Then type 'depmod -a' as root, then type 'update-initramfs -u' as root.

And...since you may want non-root users to mess w/ the LED's, you put the following into /etc/udev/rules.d/00-aw-elc.rules:
SUBSYSTEM=="usb", ATTRS{idVendor}=="187c", ATTRS{idProduct}=="0550", MODE="0660", GROUP="plugdev", SYMLINK+="awelc"

Then make sure that your chosen users are in the 'plugdev' group. I created the symlink in case I needed it later. Modify as you like. Then reboot to make sure everything takes effect properly (or rmmod and modprobe, etc)

The modprobe and udev lines should solve a number of the issues seen above (can't find device, can only work w/ sudo, etc)

Now onto the API....

With previous API's, much of the control could be done with one command (command, zone, parameters). This is no longer true. There are a number of different command sequences, and the controller doesn't like it when things are done out of sequence. Thankfully, the lovely developers at Dell used an easily-decompilable (is that a word?) language (C# maybe?), so I was able to eek out most of the commands by staring at and meditating over the produced source code. That being said, terminology below will be copied from the analyzed code.

To start, I'll list the structure of a single 33-byte packet (padded w/ 0x00 when needed):
0x03 (major command) (parameters)
Pretty simple, but the parameters are largely dependent upon the major command. Here is a list of the major commands:

0x20 - Get report (Status & info queries)
0x21 - User animation
0x22 - Power animation
0x23 - Start series
0x24 - Add action
0x25 - Set event (no idea what this actually does; I didn't see it used in the source code, so it may not be implemented)
0x26 - Set Dim
0x27 - Set Color (only seems to work for the Macro key zone)
0x28 - Reset (also didn't see this used, so unsure)
0xff - Erase SPI Flash (maybe setup for firmware flashing; not sure)

For command 0x20, the first parameter is a single byte sub-command. There don't appear to be any additional parameters (with most), but you will get different replies. The reply echoes the command, and tacks on the extra information after that. Here are the subcommands:

0x00 - Get firmware version - Returns 0x 01 00 07 (corresponds to version 1.0.7 of the firmware, which seems to match what the AWCC tries to flash during install; more on that later)
0x01 - Get status - Not sure how this is used, because I never got a reply other than all 00's. Might return certain codes if the controller is busy, but I didn't stress test things.
0x02 - Get ELC Firmware Config - Returns a two-byte platform ID (Mine was 0x0104), and a number of zones. I have the standard keyboard, so my zone count was 14. That is odd, since I couldn't find 14 total zones (I only found 13). Advanced keyboards (every key) may have more. According to what I could find, my platform ID probably should be 0x0205. But whatever. Moving on...
0x03 - Get Animation Count - Returns a two byte value with the number of animations, and a two byte value with the ID of the last animation (maximum animation ID value). More on these with the next two major commands
0x04 - Get ELC Animation by ID - Not sure of the exact purpose. Always returns a string of ff's. Also appears to not be implement in the AWCC code. It appears that you provide the Animation ID as a parameter and it returns....something? Again, not sure.
0x05 - Read series - Not even sure of the proper parameters for this one. Also returns a string of ff's. Also not implemented.

Are you confused yet? No? Moving on....

Major commands 0x21 and 0x22 deal with the animations. 0x21 deals with "user animations", where the user wants to set a particular action for a particular zone not dependent upon power states. Kind of like a "running" config for those who have messed with Cisco IOS. The format of the command is the same as 0x22, so we'll talk about the structure first.

Like 0x20, there's a subcommand. But it's two bytes this time, followed by a two byte Animation ID, and a two byte duration. The subcommands are:
0x0001 - Start new animation
0x0002 - Finish & Save animation
0x0003 - Finish & Play animation
0x0004 - Remove (Erase) animation
0x0005 - Play Animation
0x0006 - Set Default animation
0x0007 - Set Startup animation

The two byte animation ID's are as follows (power state animation ID's first)
0x005b - AC Sleep
0x005c - AC On (Charged)
0x005d - AC On (Charging)
0x005e - Battery Sleep
0x005f - Battery On
0x0060 - Battery Critical

0x0061 - Chassis & Keyboard zone running states (post-startup)
0xFFFF - Chassis & Keyboard zone running states (not saved, as best as I can tell; different ID used when finishing a running state than when starting)

Duration only seems to be set when setting the startup sequence state (set to 0d6000); my guess is how long the startup sequence runs before moving to the post-startup animation state (0x0061). 6 seconds seems right, so I'm guessing the value is milliseconds.

When modifying power state animations, use major command 0x22. When modifying user animations, use major command 0x21. I'm not sure about setting the startup animation. I would expect use major command 0x21. NOTE: That's conjecture. I never saw a command to set the startup sequence in captured traffic.

Major command 0x23 deals with zone selection. First you select the zones you want to apply the action on, then you specify the action. The command does not have subcommands. It has the following parameters:
One byte - Loop? - Appears to be a boolean value, and I've only seen it set to 1 (doesn't make sense to have a morph or pulse only run once...
Two bytes - Number of zones to select
One byte for each zone selected.
So if I wanted to select the four keyboard zones, it would look like this (all in hex):
01 00 04 04 05 06 07

What are the zones? Here they are for the 17R5 w/ Std Keyboard:
00 - Alien Head (outside lid)
01 - Alienware logo (text, inside lid)
02 - Touchpad
03 - Power button (usually only selected/set when changing power animations)
04 - Numpad
05 - Keyboard Right
06 - Keyboard Center
07 - Keyboard Left
08 - Chassis Left Stripe
09 - Chassis Right Stripe
0A - Lid Left Stripe
0B - Lid Right Stripe
0C - Macro Keys (only set using the "Set Color" major command; may be able to do more, but not sure)
0D - Alien Head on graphics accelerator (probably only available if the GA is actually plugged in)

Not done yet...
Major command 0x24 is the most confusing. It is the "add action" command, and does the heavy lifting of what we actually want done. It also has subcommands, and each is followed by some fairly standard values. Here we go...

0x00 - Color
0x01 - Pulse
0x02 - Morph

Two bytes for duration (in milliseconds; 09c4 is 2500 (long), 05dc is 1500 (medium), 01f3 is 1000 (short). You get the idea.
Two bytes for tempo (00fa is 0d250 (fast), 0064 is 0d100 (slow))
One byte each for RGB values. No more 3->2 byte packing!

For the color and pulse subcommands, you're done. For all the other effect types (Morph, Breathe, Spectrum, RainbowWave), you need more. But it's easy. For the next color in the sequence, you repeat the subcommand, another duration & tempo and then your next color. Here's what a few different effects will look like:

Morph (fade from r1g1b1 to r2g2b2, then set color back):
02 d1 d1 t1 t1 r1 g1 b1 00 00 01 00 64 r2 g2 b2

Breathe (fade from r1g1b1 to black):
02 d1 d1 t1 t1 r1 g1 b1 02 d1 d1 t1 t1 00 00 00

For spectrum, we have to fade across a whole bunch of different colors, and that won't fit into one command. So it's split in to multiple commands. Here's a long example:
0324 02 0282 000f ff0000 02 0282 000f ffa500 02 0282 000f ffff00
0324 02 0282 000f 008000 02 0282 00bfff 02 0282 000f 0000ff
0324 02 0282 000f 800080
Start at red, and morph through each successive color. Note that the duration and tempo values are the same all throughout. Varying those in the sequence isn't something I've tried, but it sounds like a fun exercise.

Next major command (0x26) is Set Dim. This one has been discussed a little bit, but this is the full breakout of the parameters:
One byte - % Dim (0x64 is 100%)
One byte - Number of zones to dim
One byte for each zone

Major command 0x27 is Set Color. This appears to be only used for the macro keys; I haven't tried setting them with the other effects. This command also doesn't seem to work for any other zone; just the macro keys.
One byte each of for RGB value
Two bytes for number of zones to set (only seems to be 0x0001)
One byte for each zone to set (only seen 0x0c)

As I said, major commands 0x25 (Set event), 0x28 (Reset), and 0xFF (Erase SPI Flash) don't seem to be used in the AWCC code, and at least 25 and 28 seem to reply with a bunch of FF's, so they may not be implemented. Though while playing, I was able to erase the default running config of the chassis and keyboard zones so they stayed in the startup animation (spectrum). So one of those may remove/erase animation code 0061 so that only the startup animation would play. It's really weird trying to type on a keyboard when it's running through the rainbow....

Knowing the definition of the commands is one thing. Using them is slightly different, but not hard. There is a definite sequence to the commands to make certain changes. Let's start with a running config change:

For starters I'll only be affecting zone 01 (Alienware logo words inside the lid):
Start new user animation (command 0x21) w/ Animation ID of FFFF: 0321 0001 FFFF
Select zone 01: 0323 01 0001 01
Action; We'll use set color 00f0f0 for this example: 0324 07d0 00fa 00f0f0
Finish & Play animation (command 0x21) w/ Animation ID of 00FF (why? I don't know): 0321 0003 00FF

If you want to set the same action for more than one zone, select more than one in the zone selection command. If you want to set different effects for different zones, you can do that too. Just select the zones, add the action, select different zones, add the action (and so on). The sequence only finishes when you use the Finish & Play animation command.

When the service starts, it sets the values for each animation ID (I guess they were stored in the AWCC software and sent down just in case). For those it followed this sequence: It set up the power state animations first, then did the user default animation.

So for each power state:
Remove Animation ID (major command 0x22 and each distinct power state; two bytes)
Start new power animation (major command 0x22) w/ same Animation ID
Select zone (always was zone 3 (power button) in the capture)
Action
Finish & Save w/ same Animation ID

Then for the user state (Animation ID 0061):
Remove Animation ID (Major command 0x21 w/ Animation ID 0061)
Start new user animation (Major command 0x21 w/ Animation ID 0061)
Select zone(s)
Action
(if needed) Select more zones...
(if needed) Action)
Finish & Save w/ major command 0x21 & Animation ID 0061
Set Default w/ major command 0x21 & Animation ID 0061

I think that about covers it. I did capture the rainbow wave effect, but that is a mess of select one zone, spectrum effect, select another zone, spectrum effect (shift the color sequence slightly), and so on. Left as an exercise for the reader, because I don't feel like typing it here for now. If you're really interested, I suppose I could do it, but later (my hands are getting tired...)

Edit: I forgot to mention flashing the firmware. The firmware is flashable on Linux, but not easy. In order to place the controller in update mode, you need to call some ACPI methods, which can really only be done by the kernel. So by adding some features to the alienware-wmi kernel driver I was able to place the controller into firmware update mode. At that point, the DFU utilities can prepare and upload the firmware to the device. Hopefully we don't have to do that very often, as at the moment it's VERY manual and icky. You can also brick your controller if you're not careful.

@DenDeze
Copy link

DenDeze commented Feb 27, 2019

WoW nice write up, still confusing ;(

@kmescher
Copy link

kmescher commented Mar 16, 2019

Happy St. Patrick's Day!

Not being interested in writing a lot of raw hex, I wrote some python to take care of the hard stuff. Now it's a lot easier to explain how the protocol works. Bear with me for a moment:

Each controller has supports a set number of "animations". I expect that all of them support the same number. Six of the animations are for power states, one for default (after the boot sequence), and one for either the non-default running, or the startup sequence. Each animation could be considered a memory "slot" that you can save to.

Each animation can hold one or more "series" (not sure the maximum). Each series contains a list of zones and a flag for looping (which is almost always set to 1). Each series contains one or more actions (not sure of maximum), which is the sequential list of states that you want the LED's in that series' zones to change to. This opens up a large amount of versatility.

Previous versions of the protocol (and the AWCC program in Windoze) have a limitation on what zones can be used to reflect the power state. This limitation doesn't actually exist on the controller. For example, my 17R5 shipped with only the power button changing when I changed power states. I have set the controller so now the power button and the outside Alien head show the current power state.

So by doing the protocol manually, we have considerably more versatility than AWCC can offer us. Score!

I'm not yet sure how to integrate this code into the alienfx source tree, as the controller is capable of more than the alienfx code can deliver as well. So for the moment, I've written a python class to make commanding the controller easier. Unfortunately, you still have to know the order of the individual commands.

To change the config for a particular slot (animation), we do the following commands:

Remove animation
Start New Animation
1 or more of:
Start Series
1 or more of:
Add action (up to three actions per add action command)
Finish & Save animation

As stated in my previous post, each start series command contains:
Loop Flag (one byte, almost always 1)
Number of zones (two bytes)
List of zones (one byte each)

Each action inside an Add Action command contains:
Effect (Color, Pulse, Morph)
Duration (how long it will take to complete that action, or stay in it)
Tempo (Used really only for pulse, to determine the pace of changing)
Color (One byte for each of R, G, B)

So if I wanted to change the config for the AC_SLEEP state (0x5B), I run the following commands:
Remove Animation 0x5B
Start New Animation 0x5B
Start Series (zones 0 and 3)
Add Action ( (MORPH,2 sec duration, 100 tempo, #00F0F0), (MORPH,2 sec duration, 100 tempo, #000000)) -- This fades from a teal color to black
Finish & Save Animation 0x5B

Since the write-up can still be a little daunting, I've attached the code I wrote to make my life easier. The files are as follows:

elc.py - The classes for the ELC and an Action. These classes construct the individual commands and send them to the controller
elc_constants.py - This contains a bunch of constants to make my life easier. Each power state is documented in there as well as a constant for each command/subcommand, etc
hidreport.py - A couple of nice functions to handle the USB side of things

set_chassis_zones.py - A script which uses the ELC class to adjust the zones on my chassis (non-keyboard). Right now it's set to change the LED's from Green to White to Orange. Happy St. Patrick's Day!
set_keyboard_zones.py - Same idea, but for the four keyboard zones (4,5,6,7)
NOTE: These two don't change the default_post_boot config, so when the controller reboots these configs will be lost. To "save" them as default, you need to use state 0x61 (default post boot), and save them using the next file as a model.

set_power_states.py - Similar, but sets up each of the six power states. Note that this one uses zones 0 (outside alien head) and 3 (power button) for the states. I can do this because I have removed zone 0 from the default_post_boot state (0x61). If you I didn't do that, zone 0 would be constantly fighting between the current power state and the default_post_boot state (not pretty).

If you want to know the zone numbers and names for each of the individual models, you will need to know the platform ID of your controller (the python code has the ability to retrieve that for you). You will also need a json file with the zone definitions (which happened to be shipped with AWCC in the "DeviceFX" folder). Each json file has a 'jsondata' field which the base64 encoded JSON describing each platform. It includes the zone numbers, a textual description, as well as the VID and PID of the USB controller. Note for those of you with the advanced keyboard, that appears to have a separate VID and PID, and a large zone list. Have fun! :-D

Share and Enjoy!

elc.zip

@AbsyntheSyne
Copy link

@kmescher still a slightly confusing writeup(for me at least with no python experience) but after I studied and learned how the code worked I can fully control all of my lights! You're awesome man. :)

@DenDeze
Copy link

DenDeze commented May 23, 2019

@absythesince, could you provide your code

@ezekielnewren
Copy link

@AbsyntheSyne I'd like to see the code you wrote up. I have the Alienware 15 R4 as well, and it would be really nice if my laptop wasn't a night light.

@AbsyntheSyne
Copy link

@trackmastersteve if you could give me some help I might be able to create a working configuration file for this laptop.

@ezekielnewren
Copy link

What would you need to make this configuration file?

@AbsyntheSyne
Copy link

AbsyntheSyne commented Feb 23, 2020

The zone codes for the lights. Which we haven't been able to grab because the zonescan thing hasn't been particularly helpful

edit: never mind. I can't get anywhere, even if I had the correct zones. I've got it to recognise the correct hardware and see it in the GUI but changing the lights just maxes out my CPU.. @kmescher is there anyway you could make a GUI program for your code? It'd help a lot of people.

@AbsyntheSyne
Copy link

@AbsyntheSyne I'd like to see the code you wrote up. I have the Alienware 15 R4 as well, and it would be really nice if my laptop wasn't a night light.

What would you like to accomplish with the code? It's just edited from his, once you understand it by messing around with it, you can do anything with the controller. If only there was some way to make this into an application, but unfortunately I don't have the know-how to do it.

@haroldLuiz
Copy link

haroldLuiz commented Mar 12, 2020

@kmescher THANKS! perfect! @trackmastersteve any ideia if it is viable implementing this on the project? or would be better to just make a new one?

Useful info:
i used elc.zip on a Dell G5 5590

Hwinfo:
E: ID_VENDOR=Alienware
E: ID_VENDOR_ENC=Alienware
E: ID_VENDOR_ID=187c
E: ID_MODEL=AW-ELC
E: ID_MODEL_ENC=AW-ELC
E: ID_MODEL_ID=0550
E: ID_REVISION=0200
AlienFX says:
Found device "0x187c / 0x0550"

My "custom.py" i created and execute on boot time as root:

from elc import *
from elc_constants import *
import binascii

elc.set_color(range(0,4),0,0,255)
elc.dim(range(0,4), 0)

elc.remove_animation(AC_CHARGED)
elc.start_new_animation(AC_CHARGED)
elc.start_series(range(0,4))

elc.add_action((Action(COLOR,2000,100,0,0,255),))
elc.finish_save_animation(AC_CHARGED)

elc.remove_animation(DC_ON)
elc.start_new_animation(DC_ON)
elc.start_series(range(0,4))

elc.add_action((Action(COLOR,2000,100,0,0,0),))
elc.finish_save_animation(DC_ON)

elc.remove_animation(DC_LOW)
elc.start_new_animation(DC_LOW)
elc.start_series(range(0,4))

elc.add_action((Action(COLOR,2000,100,255,0,0),))
elc.finish_save_animation(DC_LOW)


if __name__ == "__main__":
        main()

Keyboard is Blue while charging, lights are off on battery

lights turn red if low on battery (theoretically, didn't test yet)

@AbsyntheSyne
Copy link

@haroldLuiz how would one set the python script to launch on boot?

@haroldLuiz
Copy link

haroldLuiz commented Mar 16, 2020

@haroldLuiz how would one set the python script to launch on boot?

I did add sudo /opt/elc/custom.py to my $HOME/.profile, but that did work because my user has ALL=(ALL) NOPASSWD: ALL on the /etc/sudoers, a better option for most people would be probaly be setting it up on /etc/init.d/ or crontab.
Google can answer easily how to do that.

@Cheaterman
Copy link

Cheaterman commented Sep 2, 2020

Happy St. Patrick's Day!

...

elc.zip

This is a lifesaver, thanks a lot!

EDIT: And hard to find, too. "AlienFX Linux" wouldn't be enough - basically I've been lucky to get a match when looking for exact vid/pid... That 0x0550 device being so different from the previous versions really is a pain. The lack of documentation is also annoying!

@ShimmerFairy
Copy link

I have an Aurora R10 desktop with the same controller (zonescan says Found device "0x187c / 0x0550".). I have to ask, do all those power states mentioned exist in the desktop version of the controller (I'd assume so)? And more importantly, if they do exist, can they all be triggered on a desktop where charging isn't really a thing? For what it's worth I'm not interested in changing color based on power states (again, it's a desktop), I just think it'd be helpful to know how this controller operates in desktops as well as laptops.

@Cheaterman
Copy link

Cheaterman commented Sep 7, 2020

I did a bit of extra abstraction on top of @kmescher's work, check it out here: https://gist.github.com/Cheaterman/accd912c6886f4055f45d0594b88553c

Basically used all of @kmescher's reverse-engineering work, and combined it with some USB tricks already present in AlienFX, all in a nice OOP package by yours truly.

Here a (very) basic example file: https://gist.github.com/2d166b510adc5eb9d582eaa83282c410

Here a simple zone tester (for zones 4-16 - change inside file as needed): https://gist.github.com/6911515cb12bce63e5548989b513840a

I hope y'all enjoy :-)

EDIT: @ShimmerFairy The only real way to know is for you to try I suppose? I expect only AC_* to work for you, so you should have at least normal + suspend?

@kmescher
Copy link

kmescher commented Sep 7, 2020

The AlienFX package includes a big pile of json files which specify the zones for each machine type (and their numbers), and if they are used to reflect power status.

In the case of the Aurora 10, I couldn't find a file for that machine type specifically, but I did find one for the Aurora R9 and R11.

R9:
Zone 0: Power button
Zone 1: Front Ring
Zone 2: Alienware Logo (only on the "Upsell" version)

The R11 is similar, but the "Upsell" version has these zones instead:
Zone 2: Back Lighting
Zone 3: Alienware Logo

Unfortunately, it appears (according to the json files) that none of the zones can reflect the power state. The power states may exist on the controller, but it appears that they won't do you any good.

As of March 2020, Dell pushed out a new firmware version for this controller (1.0.11). I haven't loaded that on my system or seen if it has any new capabilities.

EDIT: Additional note: If you have one of the fancy keyboards (where each key is a separate zone), the json files have all the zone numbers for those keys. At least for the 15R4 laptop, the vendor and device ID are WAY different than for the rest of the system, and there are 135 individual zones (one for each regular key), and 1 zone (ID 999) for the macro keys. If anyone wants to request the list for a particular machine type, let me know.

@Cheaterman: There are some files for the Dell G5 5500 series. Looks like zones 0-3 are for the RGB keyboard (left, center, right, keypad), and zones 4-15 are listed as "Light bar 1" through "Light bar 12".

@Cheaterman
Copy link

@kmescher whoa, thanks for the info! Do you think you could publish the full list of JSON files? I don't think any of us have your reverse-engineering talent, haha! Thanks in advance :-)

@gemarcano
Copy link

@kmescher, this is a long shot, but do you know (or still have a list of) what are the ACPI methods that need to be poked at to set the RGB microcontroller to DFU mode?

I've been poking at this for kicks and giggles, and I've figured out that at least on my Dell G5 5505 SE the internal controller appears to be a STM32F070x6 or STM32F070xB, and I did find the Windows applications that the Alienware software uses to flash the firmware (ElcUpdate.exe and friends). From poking around the updater, I know that there are two GPIOs that are toggled (NRST and BOOT0) to change modes, but I'm having a hard time figuring out what the heck Windows does to toggle those GPIOs (I know it's ACPI related, but that's about it for now, can't narrow down the methods being used). If I can figure that out, I can easily whip up a kernel module in Linux.

@gemarcano
Copy link

In case anyone stumbles upon this while searching online (as no one else talks about the DFU in some of these Dell systems), I haven't yet found a complete solution, but I unstuck myself, effectively bridging the gap between the updater and whatever Windows is doing.

In Windows, one can probe the specific ACPI WMI object through Get-WmiObject in Powershell. Specifically:

$obj=Get-WmiObject -Namespace "ROOT/WMI" -Class AWCCWmiMethodFunction

Should save the returned WMI class into the $obj variable for inspection. Windows reports the relative path to be something along the lines of ACPI\PNP0C14\AWCC_0, which is in the WMI instance in the ACPI tables.

Thing is, I wasn't able to find any mention of anything resembling AWCC in the DSDT ACPI table. Clearly, though, Windows was reading this from an ACPI table. After decompiling all of my ACPI tables using iasl I identified table SSDT19 as having the definition of the methods! Additionally, the MOF binary (WQMO) in the table can be dumped using https://github.com/pali/bmfdec , and I confirmed that the data there provided the names Windows was displaying with the AWCCWmiMethodFunction class.

I still haven't completely figured out how to switch the MCU to DFU mode, but I think I now have enough information to get there. Although, if someone has Linux kernel code that works, that would be great! One advantage of figuring out how this works is being able to update the firmware on these chips, and if someone REs the firmware, that means custom firmware that doesn't suck as much as Dell's! Imagine being able to query which zones are turned on!

@gemarcano
Copy link

This'll likely be the last time I post here, just since this issue is closed and not about my misadventures, but again, this is the only page that shows up when looking up alienfx DFU, or alienware DFU and the like.

I succeeded in deciphering enough that I can also now switch the STM32F070xB (yes, I narrowed it down to have 128KB of flash) to its bootloader mode, and dump its internal flash using dfu-utils.

The gist of it is in the SSDT19 ACPI table, the _SB.AMWW.WMAX method. Specifically, it has a switch case to do different functions. For toggling the pins the method values is 32. There is a value for querying the state of the pins, 34, but there's a bug in the DSDT WISC method that actually handles the GPIO pin stuff, that makes it so querying the status will always disable the pin output. I've patched my DSDT to fix that particular bug.

I'll probably write up something about this somewhere else, and I may upload some Linux kernel code that can toggle these GPIO pins around through WMI commands.

@kmescher
Copy link

kmescher commented Apr 13, 2022 via email

@T-Troll
Copy link

T-Troll commented Nov 27, 2022

Wow! I just found for this topic.

I'm the guy who develop (AlienFX-Tools)[https://github.com/T-Troll/alienfx-tools/]

In fact, all AWCC-based functions exposed into WMI via AWCCWmiMethodFunction class methods. But light control only available at older systems, latest m-series, x-series and g-series doesn't support it.

Also, i't a lot of unclear points into your 0x550 chip description, especially about power block set (it's tricky), as well as some other stuff.

In case you're still interested, let's share out research results.

@James4Ever0
Copy link

i just got my fingers on a 17R5 which uses the same controller.

Working on a solution. Please be patient.

I have a 17r5 too. VID: 0x187c / DEV: 0x0550

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests