diff --git a/Controllers/SkydimoSerialController/RGBController_SkydimoSerial.cpp b/Controllers/SkydimoSerialController/RGBController_SkydimoSerial.cpp index 482369c4e..9a8e7265f 100644 --- a/Controllers/SkydimoSerialController/RGBController_SkydimoSerial.cpp +++ b/Controllers/SkydimoSerialController/RGBController_SkydimoSerial.cpp @@ -11,6 +11,11 @@ #include "RGBController_SkydimoSerial.h" +using namespace std::chrono_literals; + +#define SKYDIMO_SERIAL_SLEEP_THRESHOLD 100ms +#define SKYDIMO_SERIAL_KEEPALIVE_PERIOD 1500ms + /**------------------------------------------------------------------*\ @name Skydimo Serial @category LEDStrip @@ -41,12 +46,19 @@ RGBController_SkydimoSerial::RGBController_SkydimoSerial(SkydimoSerialController modes.push_back(direct_mode); SetupZones(); + + last_update_time = std::chrono::steady_clock::now(); + keepalive_thread_run = true; + keepalive_thread = std::thread(&RGBController_SkydimoSerial::KeepaliveThreadFunction, this); } RGBController_SkydimoSerial::~RGBController_SkydimoSerial() { Shutdown(); + keepalive_thread_run = false; + keepalive_thread.join(); + controller->SetBlack(); delete controller; } @@ -129,6 +141,8 @@ void RGBController_SkydimoSerial::DeviceConfigureZone(int zone_idx) void RGBController_SkydimoSerial::DeviceUpdateLEDs() { + last_update_time = std::chrono::steady_clock::now(); + controller->SetLEDs(colors); } @@ -145,3 +159,29 @@ void RGBController_SkydimoSerial::DeviceUpdateSingleLED(int) void RGBController_SkydimoSerial::DeviceUpdateMode() { } + +void RGBController_SkydimoSerial::KeepaliveThreadFunction() +{ + std::chrono::nanoseconds sleep_time; + + while(keepalive_thread_run.load()) + { + sleep_time = SKYDIMO_SERIAL_KEEPALIVE_PERIOD + - (std::chrono::steady_clock::now() - last_update_time); + + if(sleep_time <= SKYDIMO_SERIAL_SLEEP_THRESHOLD) + { + /*-----------------------------------------------------*\ + | SK0L32 turns its output off when it does not receive | + | a frame for a short period. Repeat the current frame | + | while the device is connected, like the vendor app. | + \*-----------------------------------------------------*/ + UpdateLEDsInternal(); // Already protected through the device update thread + std::this_thread::sleep_for(SKYDIMO_SERIAL_KEEPALIVE_PERIOD); + } + else + { + std::this_thread::sleep_for(sleep_time); + } + } +} diff --git a/Controllers/SkydimoSerialController/RGBController_SkydimoSerial.h b/Controllers/SkydimoSerialController/RGBController_SkydimoSerial.h index ff473f544..a820805dd 100644 --- a/Controllers/SkydimoSerialController/RGBController_SkydimoSerial.h +++ b/Controllers/SkydimoSerialController/RGBController_SkydimoSerial.h @@ -11,6 +11,8 @@ #pragma once +#include +#include #include "RGBController.h" #include "SkydimoSerialController.h" @@ -28,6 +30,11 @@ public: void DeviceUpdateSingleLED(int led); void DeviceUpdateMode(); + void KeepaliveThreadFunction(); + private: - SkydimoSerialController* controller; + SkydimoSerialController* controller; + std::chrono::time_point last_update_time; + std::atomic keepalive_thread_run; + std::thread keepalive_thread; }; diff --git a/Controllers/SkydimoSerialController/SkydimoSerialController.cpp b/Controllers/SkydimoSerialController/SkydimoSerialController.cpp index 523c36fa3..adc0b8f35 100644 --- a/Controllers/SkydimoSerialController/SkydimoSerialController.cpp +++ b/Controllers/SkydimoSerialController/SkydimoSerialController.cpp @@ -436,8 +436,15 @@ bool SkydimoSerialController::WriteFrame(const std::vector& colors, un packet.push_back(skydimo_serial_frame_header[header_idx]); } - packet.push_back((unsigned char)((count >> 8) & 0xFF)); - packet.push_back((unsigned char)(count & 0xFF)); + /*-----------------------------------------------------*\ + | Skydimo uses the Adalight length convention: the | + | 16-bit field contains the last LED index, not the | + | number of LEDs. | + \*-----------------------------------------------------*/ + unsigned int frame_length = count > 0 ? count - 1 : 0; + + packet.push_back((unsigned char)((frame_length >> 8) & 0xFF)); + packet.push_back((unsigned char)(frame_length & 0xFF)); for(unsigned int led_idx = 0; led_idx < count; led_idx++) {