DarthAffe / RGB.NET

The one-stop SDK for RGB-peripherals

Home Page:http://lib.arge.be

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Asus sdk problem

Lumiond opened this issue · comments

As we know, asus sdk can be unstable in c#.
I post in discord these examples a few month ago:
working - https://pastebin.com/ARCJtWiN
non-working - https://pastebin.com/a66ZdGi0

I thought that problem is in asus aura sdk but after reading some articles I think problem is "how c# works with com objects" (and asus sdk is com object of course). Also I have found wrapper for unity from asus (it doesn't work in unity, he-he, but it doesn't matter) and have seen interesting thing: they use c# class AuraDevice. This class contain IAuraSyncDevice, array of IAuraRgbLight, device type and some device info like animation type, width. height etc. I try to use this idea in my synthetic example. And it works! Two days, 10 hours of stable work without any problem. Also, I have tried to cut array of IAuraRgbLight from my class and have got crash after 1 hour (as usual). Unfortunately, I don't understand architecture of RGB.NET at sufficient level so I can't implement a fix. But I provide my working example and hope that it's helpful and we get fully working stuff. I think that this implementation change time of object life so we get stable work. My code:

using System.Runtime;
using AuraServiceLib;
using System.Threading;
using System.Collections.Generic;

namespace SharpAuraTestImport5
{
    class AuraDev
    {
        public uint devType;
        public IAuraSyncDevice device;
        public IAuraRgbLight[] lightArray;
    }
    class Program
    {
        static void Main(string[] args)
        {
            List<AuraDev> devList = new List<AuraDev>();
            IAuraSdk2 sdk = (IAuraSdk2)new AuraSdk();
            try
            {
                sdk.SwitchMode();
                IAuraSyncDeviceCollection devices = sdk.Enumerate(0);       // 0 means all
                devList.Clear();
                foreach (IAuraSyncDevice dev in devices)
                {
                    if (dev.Name != "Termial 2")
                    {
                        AuraDev auraDev = new AuraDev()
                        {
                            devType = dev.Type,
                            device = dev,
                            lightArray = new IAuraRgbLight[dev.Lights.Count],
                        };
                        uint num = 0;
                        foreach (IAuraRgbLight light in dev.Lights)
                            auraDev.lightArray[(int)num++] = light;
                        devList.Add(auraDev);
                    }
                }
                int count = 0;
                while (true)
                {
                    foreach (AuraDev dev in devList)
                    {
                        foreach (IAuraRgbLight light in dev.lightArray)
                        { 
                            if (count == 0)
                            {
                                light.Color = 0x00FF0000;
                            }
                            else if (count == 1)
                            {
                                light.Color = 0x0000FF00;
                            }
                            else
                            {
                                light.Color = 0x000000FF;
                            };
                        };
                        dev.device.Apply();
                    }
                    if (count != 2) count += 1;
                    else count = 0;
                    Thread.Sleep(33);
                }
                sdk.ReleaseControl(0);
            }
            catch
            {
                sdk.ReleaseControl(0);
            }

        }
    }
}

So. I change AsusUpdateQueue class:

  1. Add IAuraRgbLight array
    IAuraRgbLight[] lightArray
  2. Add this in constructor:
lightArray = new IAuraRgbLight[device.Lights.Count];
uint num = 0;
foreach (IAuraRgbLight light in device.Lights)
    lightArray[(int)num++] = light;
  1. In update method I change this:
- IAuraRgbLight light = Device.Lights[index];
+ IAuraRgbLight light = lightArray[index];

Unfortunately, I don't know how to be with keyboard (and I don't have asus keyboard to test).
And after this changes Artemis works about 9 hours without crashes! Maybe we need add something else but I just wanted to test idea - add array of IAuraRgbLight and see what happens. And seems like I don't have memory leak.

@DarthAffe , good luck with fix and I hope that my help is useful.

@DarthAffe do you want to try these changes out in Artemis?

@DarthAffe , @SpoinkyNL , guys, any ETA for fix of this issue?

Hi, it's up to Darth but it might be useful if you put these changes in a PR. Then we can easily get a special build of the Artemis plugin to give people for testing

If you can't figure out how to do so, I can perhaps take a look this week

Unfortunately, I'm bad in c#. I can try, but I don't know if I can. I don't understand at all how to rewrite keyboard logic. And of course I think that good c# programmer can do this fix better.
My current code is like this (I have commented with "!!!" what I changed):

using System;
using AuraServiceLib;
using RGB.NET.Core;

namespace RGB.NET.Devices.Asus
{
    /// <inheritdoc />
    /// <summary>
    /// Represents the update-queue performing updates for asus devices.
    /// </summary>
    public class AsusUpdateQueue : UpdateQueue
    {
        #region Properties & Fields

        /// <summary>
        /// The device to be updated.
        /// </summary>
        protected IAuraSyncDevice Device { get; }
        protected IAuraRgbLight[] lightArray; //!!! add this array; this prevent from garbage collector deletion of links to com object
        #endregion

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="AsusUpdateQueue"/> class.
        /// </summary>
        /// <param name="updateTrigger">The update trigger used by this queue.</param>
        public AsusUpdateQueue(IDeviceUpdateTrigger updateTrigger, IAuraSyncDevice device)
            : base(updateTrigger)
        {
            this.Device = device;
// !!! this is for array init
            lightArray = new IAuraRgbLight[device.Lights.Count];
            uint num = 0;
            foreach (IAuraRgbLight light in device.Lights)
                lightArray[(int)num++] = light;
// !!!
        }

        #endregion

        #region Methods

        /// <inheritdoc />
        protected override void Update(in ReadOnlySpan<(object key, Color color)> dataSet)
        {
            try
            {
                if ((Device.Type == (uint)AsusDeviceType.KEYBOARD_RGB) || (Device.Type == (uint)AsusDeviceType.NB_KB_RGB))
                {
                    if (Device is not IAuraSyncKeyboard keyboard)
                        return;

                    foreach ((object customData, Color value) in dataSet)
                    {
                        (AsusLedType ledType, int id) = (AsusKeyboardLedCustomData)customData;
                        if (ledType == AsusLedType.Key)
                        {
                            IAuraRgbLight light = keyboard.Key[(ushort)id];
                            (_, byte r, byte g, byte b) = value.GetRGBBytes();
                            light.Red = r;
                            light.Green = g;
                            light.Blue = b;
                        }
                        else
                        {
                            IAuraRgbLight light = keyboard.Lights[id];
                            (_, byte r, byte g, byte b) = value.GetRGBBytes();
                            light.Red = r;
                            light.Green = g;
                            light.Blue = b;
                        }
                    }
                }
                else
                {
                    foreach ((object key, Color value) in dataSet)
                    {
                        int index = (int)key;
                        IAuraRgbLight light = lightArray[index]; // !!! and in update loop we must set lights from our array, not from device

                        (_, byte r, byte g, byte b) = value.GetRGBBytes();
                        light.Red = r;
                        light.Green = g;
                        light.Blue = b;
                    }
                }

                Device.Apply();
            }
            catch
            { /* "The server threw an exception." seems to be a thing here ... */
            }
        }

        #endregion
    }
}

I have been using my custom dll already one month and don't have any problem (I use ambilight profile for 4 strips on monitor - connected through aura terminal - and my own profile: "wave" effect + particles + static background for Maximus IX Hero + second aura terminal with 3 strips + RAM).