Skip to content

Commit

Permalink
Implement ftdi apa102 device
Browse files Browse the repository at this point in the history
  • Loading branch information
nurikk-sa committed Feb 24, 2024
1 parent 695c6a7 commit b7eb508
Show file tree
Hide file tree
Showing 22 changed files with 1,064 additions and 33 deletions.
2 changes: 1 addition & 1 deletion .github/actions/codeql/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ runs:
git \
libasound2-dev \
libegl-dev \
libftdi-dev \
libftdi1-dev \
libgl-dev \
libglvnd-dev \
libpipewire-0.3-dev \
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ compile_commands.json
sources/flatbufserver/hyperhdr_reply_generated.h
sources/flatbufserver/hyperhdr_request_generated.h

# turbojpeg and ftdi windows libraries
dependencies/windows

external/windows

Expand Down
92 changes: 67 additions & 25 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ SET ( DEFAULT_BONJOUR ON )
SET ( DEFAULT_MQTT ON )
SET ( DEFAULT_STATIC_QT_PLUGINS OFF )
SET ( DEFAULT_PRECOMPILED_HEADERS ON )
SET ( DEFAULT_FTDIDEV ON )
SET ( DEFAULT_XZ ON )
SET ( DEFAULT_POWER_MANAGEMENT ON )

Expand Down Expand Up @@ -340,6 +341,9 @@ colorMe("ENABLE_SPIDEV = " ${ENABLE_SPIDEV})
option(ENABLE_WS281XPWM "Enable the WS281x-PWM device" ${DEFAULT_WS281XPWM} )
colorMe("ENABLE_WS281XPWM = " ${ENABLE_WS281XPWM})

option(ENABLE_FTDIDEV "Enable the FTDI device" ${DEFAULT_FTDIDEV})
colorMe("ENABLE_FTDIDEV = " ${ENABLE_FTDIDEV})

message( STATUS "\n${CyanColor}SOFTWARE GRABBERS${ColorReset}")

option(ENABLE_DX "Enable Windows DirectX 11 system grabber" ${DEFAULT_DX})
Expand Down Expand Up @@ -546,50 +550,88 @@ endif()

add_definitions(${QT_DEFINITIONS})

# libjpegturbo
if(WIN32)
if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/external/windows)
file(MAKE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/external/windows)
# libjpegturbo and ftdi libraries

if( WIN32 AND (ENABLE_MF OR ENABLE_FTDIDEV))
if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/dependencies/windows)
file(MAKE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/dependencies/windows)
endif()

if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/external/windows/libs4windows.zip OR
NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/external/windows/libjpeg-turbo_x64-windows)
message( STATUS "Downloading libraries for HyperHDR (Windows)")
file(DOWNLOAD https://github.com/awawa-dev/HyperHDR.libs.provider/releases/download/2023.08.07/libs4windows.zip
${CMAKE_CURRENT_SOURCE_DIR}/external/windows/libs4windows.zip
STATUS WIN_LIBS_DOWNLOAD_STATUS
EXPECTED_HASH SHA256=2a0fc14eaad35d8cc36b262c8dcb501d1fac3a72d7bedcca51b71b60395c6c3f)
if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/dependencies/windows/libs4windows.zip OR
NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/dependencies/windows/libjpeg-turbo_x64-windows OR
NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/dependencies/windows/libftdi1_x64-windows)
message( STATUS "Downloading libjpegturbo and ftdi libraries")
file(DOWNLOAD https://github.com/awawa-dev/HyperHDR.libs.provider/releases/download/2023.04.10/libs4windows.zip
${CMAKE_CURRENT_SOURCE_DIR}/dependencies/windows/libs4windows.zip
STATUS WIN_LIBS_DOWNLOAD_STATUS
EXPECTED_HASH MD5=46d91068c9a97d79f74e899dbbeb027b)
list(GET WIN_LIBS_DOWNLOAD_STATUS 0 WIN_LIBS_DOWNLOAD_STATUS_CODE)
if(WIN_LIBS_DOWNLOAD_STATUS_CODE AND NOT WIN_LIBS_DOWNLOAD_STATUS_CODE EQUAL 0)
file( REMOVE ${CMAKE_CURRENT_SOURCE_DIR}/external/windows/libs4windows.zip )
message( FATAL_ERROR "Could not download libraries needed by HyperHDR (Windows)")
file( REMOVE ${CMAKE_CURRENT_SOURCE_DIR}/dependencies/windows/libs4windows.zip )
message( FATAL_ERROR "Could not download libjpegturbo and ftdi libraries")
endif()
endif()

execute_process(
COMMAND ${SEVENZIP_BIN} x ${CMAKE_CURRENT_SOURCE_DIR}/external/windows/libs4windows.zip -o${CMAKE_CURRENT_SOURCE_DIR}/external/windows/ -aoa -y
COMMAND ${SEVENZIP_BIN} x ${CMAKE_CURRENT_SOURCE_DIR}/dependencies/windows/libs4windows.zip -o${CMAKE_CURRENT_SOURCE_DIR}/dependencies/windows/ -aoa -y
RESULT_VARIABLE STATUS_EXTRACT
OUTPUT_VARIABLE OUTPUT1
)

if(STATUS_EXTRACT AND NOT STATUS_EXTRACT EQUAL 0)
message( FATAL_ERROR "Could not extract libraries for HyperHDR (Windows)")
message( FATAL_ERROR "Could not extract libjpegturbo and ftdi Windows libraries")
else()
message( STATUS "Package of libraries for HyperHDR extracted (Windows)")
message( STATUS "Package of libjpegturbo and ftdi libraries extracted")
endif()

set (TURBOJPEG_FOUND 1)
set (TURBOJPEG_LIBRARY_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/external/windows/libjpeg-turbo_x64-windows/bin")
set (TURBOJPEG_LINK_LIBRARIES "${CMAKE_CURRENT_SOURCE_DIR}/external/windows/libjpeg-turbo_x64-windows/lib/turbojpeg.lib")
set (TURBOJPEG_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/external/windows/libjpeg-turbo_x64-windows/include")
else()
set (TURBOJPEG_LIBRARY_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/windows/libjpeg-turbo_x64-windows/bin")
set (TURBOJPEG_LINK_LIBRARIES "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/windows/libjpeg-turbo_x64-windows/lib/turbojpeg.lib")
set (TURBOJPEG_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/windows/libjpeg-turbo_x64-windows/include")

set (LIB_FTDI_FOUND 1)
set (LIB_FTDI_LIBRARY_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/windows/libftdi1_x64-windows/bin")
set (LIB_FTDI_LINK_LIBRARIES "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/windows/libftdi1_x64-windows/lib/ftdi1.lib")
set (LIB_FTDI_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/windows/libftdi1_x64-windows/include/libftdi1")

set (LIB_USB_FOUND 1)
set (LIB_USB_LIBRARY_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/windows/libusb_x64-windows/bin")
set (LIB_USB_LINK_LIBRARIES "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/windows/libusb_x64-windows/lib/libusb-1.0.lib")
set (LIB_USB_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/windows/libusb_x64-windows/include/libusb-1.0")

set (LIB_CONFUSE_LIBRARY_FOUND 1)
set (LIB_CONFUSE_LIBRARY_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/windows/libconfuse_x64-windows/bin")
endif()

if ( NOT WIN32 AND ENABLE_FTDIDEV )
FIND_PACKAGE(PkgConfig REQUIRED)
pkg_check_modules(LIB_FTDI REQUIRED libftdi1)
pkg_check_modules(LIB_USB REQUIRED libusb-1.0)
endif()

if ( ENABLE_V4L2 )
FIND_PACKAGE(PkgConfig REQUIRED)
pkg_check_modules(TURBOJPEG REQUIRED libturbojpeg>=2.0)
endif ()
endif()

if( ENABLE_FTDIDEV )
if ( LIB_CONFUSE_LIBRARY_FOUND )
message( STATUS "LIB_CONFUSE_LIBRARY_DIRS=${LIB_CONFUSE_LIBRARY_DIRS}" )
endif()

message( STATUS "TURBOJPEG_LIBRARY_DIRS=${TURBOJPEG_LIBRARY_DIRS}")
message( STATUS "TURBOJPEG_LINK_LIBRARIES=${TURBOJPEG_LINK_LIBRARIES}")
message( STATUS "TURBOJPEG_INCLUDE_DIRS=${TURBOJPEG_INCLUDE_DIRS}")
message( STATUS "LIB_USB_LIBRARY_DIRS=${LIB_USB_LIBRARY_DIRS}" )
message( STATUS "LIB_USB_LINK_LIBRARIES=${LIB_USB_LINK_LIBRARIES}" )
message( STATUS "LIB_USB_INCLUDE_DIRS=${LIB_USB_INCLUDE_DIRS}" )

message( STATUS "LIB_FTDI_LIBRARY_DIRS=${LIB_FTDI_LIBRARY_DIRS}" )
message( STATUS "LIB_FTDI_LINK_LIBRARIES=${LIB_FTDI_LINK_LIBRARIES}" )
message( STATUS "LIB_FTDI_INCLUDE_DIRS=${LIB_FTDI_INCLUDE_DIRS}" )
endif()

if( ENABLE_MF OR ENABLE_V4L2 )
message( STATUS "TURBOJPEG_LIBRARY_DIRS=${TURBOJPEG_LIBRARY_DIRS}" )
message( STATUS "TURBOJPEG_LINK_LIBRARIES=${TURBOJPEG_LINK_LIBRARIES}" )
message( STATUS "TURBOJPEG_INCLUDE_DIRS=${TURBOJPEG_INCLUDE_DIRS}" )

# Embedded QT plugins
if (USE_STATIC_QT_PLUGINS)
Expand Down Expand Up @@ -633,7 +675,7 @@ include (${CMAKE_CURRENT_SOURCE_DIR}/cmake/packages.cmake)

# external targets
if (WIN32 AND TARGET apidoc AND TARGET flatbuffers AND TARGET flatc AND TARGET mbedcrypto AND TARGET qmqtt AND TARGET liblzma)
set_target_properties(qmqtt apidoc flatbuffers flatc lib mbedcrypto mbedtls mbedx509 resources uninstall liblzma PROPERTIES FOLDER ExternalLibsTargets)
set_target_properties(qmqtt apidoc flatbuffers flatc lib mbedcrypto mbedtls mbedx509 resources uninstall liblzma PROPERTIES FOLDER ExternalLibsTargets)
else()
set_target_properties(resources uninstall PROPERTIES FOLDER ExternalLibsTargets)
endif()
Expand Down
57 changes: 57 additions & 0 deletions cmake/Dependencies.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -612,6 +612,63 @@ macro(DeployWindows TARGET)
)
endif()

# Copy FTDI Libs
if (ENABLE_FTDIDEV)
find_file(FTDIDEV_DLL
NAMES "ftdi1.dll"
PATHS "${LIB_FTDI_LIBRARY_DIRS}"
NO_DEFAULT_PATH
REQUIRED
)

if(NOT CMAKE_GITHUB_ACTION)
get_filename_component(FTDI_RUNTIME_TARGET ${TARGET_FILE} DIRECTORY)
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different ${FTDIDEV_DLL} ${FTDI_RUNTIME_TARGET})
endif()

install(
FILES ${FTDIDEV_DLL}
DESTINATION "bin"
COMPONENT "HyperHDR"
)

find_file(LIBUSB_DLL
NAMES "libusb-1.0.dll"
PATHS "${LIB_USB_LIBRARY_DIRS}"
NO_DEFAULT_PATH
REQUIRED
)

if(NOT CMAKE_GITHUB_ACTION)
get_filename_component(LIBUSB_RUNTIME_TARGET ${TARGET_FILE} DIRECTORY)
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different ${LIBUSB_DLL} ${LIBUSB_RUNTIME_TARGET})
endif()

install(
FILES ${LIBUSB_DLL}
DESTINATION "bin"
COMPONENT "HyperHDR"
)

find_file(LIBCONFUSE_DLL
NAMES "libconfuse.dll"
PATHS "${LIB_CONFUSE_LIBRARY_DIRS}"
NO_DEFAULT_PATH
REQUIRED
)

if(NOT CMAKE_GITHUB_ACTION)
get_filename_component(LIBCONFUSE_RUNTIME_TARGET ${TARGET_FILE} DIRECTORY)
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different ${LIBUSB_DLL} ${LIBCONFUSE_RUNTIME_TARGET})
endif()

install(
FILES ${LIBCONFUSE_DLL}
DESTINATION "bin"
COMPONENT "HyperHDR"
)
endif()

# Copy MQTT Libs
if (ENABLE_MQTT)
set (MQTT_TARGET_LIB_FOLDER ${LIBRARY_OUTPUT_PATH}/${CMAKE_BUILD_TYPE})
Expand Down
7 changes: 6 additions & 1 deletion include/utils/ColorRgbw.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,12 @@ namespace RGBW {
SUBTRACT_MINIMUM,
SUB_MIN_WARM_ADJUST,
SUB_MIN_COOL_ADJUST,
WHITE_OFF
WHITE_OFF,
HYPERSERIAL_COLD_WHITE,
HYPERSERIAL_NEUTRAL_WHITE,
WLED_AUTO,
WLED_AUTO_MAX,
WLED_AUTO_ACCURATE
};

WhiteAlgorithm stringToWhiteAlgorithm(const QString& str);
Expand Down
4 changes: 4 additions & 0 deletions sources/hyperhdr/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,10 @@ if (ENABLE_PIPEWIRE)
target_link_libraries(hyperhdr Pipewire-grabber "${CMAKE_DL_LIBS}")
endif ()

if (ENABLE_FTDIDEV)
target_link_libraries(hyperhdr ${LIB_FTDI_LINK_LIBRARIES} ${LIB_USB_LINK_LIBRARIES})
endif ()

if (ENABLE_MAC_SYSTEM)
target_link_libraries(hyperhdr
MACOS-grabber
Expand Down
11 changes: 11 additions & 0 deletions sources/leddevice/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ include_directories(
dev_spi
dev_rpi_pwm
dev_tinker
dev_ftdi
)

FILE ( GLOB Leddevice_SOURCES
Expand All @@ -43,6 +44,10 @@ if ( ENABLE_SPIDEV )
FILE ( GLOB Leddevice_SPI_SOURCES "${CURRENT_SOURCE_DIR}/dev_spi/*.h" "${CURRENT_SOURCE_DIR}/dev_spi/*.cpp")
endif()

if ( ENABLE_FTDIDEV )
FILE ( GLOB Leddevice_FTDI_SOURCES "${CURRENT_SOURCE_DIR}/dev_ftdi/*.h" "${CURRENT_SOURCE_DIR}/dev_ftdi/*.cpp")
endif()

if ( ENABLE_WS281XPWM )
include_directories(../../external/rpi_ws281x)
FILE ( GLOB Leddevice_PWM_SOURCES "${CURRENT_SOURCE_DIR}/dev_rpi_pwm/*.h" "${CURRENT_SOURCE_DIR}/dev_rpi_pwm/*.cpp")
Expand All @@ -58,6 +63,7 @@ SET( Leddevice_SOURCES
${Leddevice_TINKER_SOURCES}
${Leddevice_SPI_SOURCES}
${Leddevice_PWM_SOURCES}
${Leddevice_FTDI_SOURCES}
)

# auto generate header file that include all available leddevice headers
Expand Down Expand Up @@ -113,3 +119,8 @@ endif()
if(USE_PRECOMPILED_HEADERS AND COMMAND target_precompile_headers)
target_precompile_headers(leddevice REUSE_FROM precompiled_hyperhdr_headers)
endif()

if(ENABLE_FTDIDEV)
target_include_directories(leddevice PRIVATE ${LIB_FTDI_INCLUDE_DIRS} ${LIB_USB_INCLUDE_DIRS})
target_link_libraries(leddevice ${LIB_FTDI_LINK_LIBRARIES} ${LIB_USB_LINK_LIBRARIES})
endif()
3 changes: 3 additions & 0 deletions sources/leddevice/LedDeviceSchemas.qrc
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,8 @@
<file alias="schema-yeelight">schemas/schema-yeelight.json</file>
<file alias="schema-cololight">schemas/schema-cololight.json</file>
<file alias="schema-awa_spi">schemas/schema-awa_spi.json</file>
<file alias="schema-ws2812_ftdi">schemas/schema-ws2812_ftdi.json</file>
<file alias="schema-apa102_ftdi">schemas/schema-apa102_ftdi.json</file>
<file alias="schema-sk6812_ftdi">schemas/schema-sk6812_ftdi.json</file>
</qresource>
</RCC>
53 changes: 53 additions & 0 deletions sources/leddevice/dev_ftdi/LedDeviceAPA102_ftdi.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#include "LedDeviceAPA102_ftdi.h"

#define LED_HEADER 0b11100000
#define LED_BRIGHTNESS_FULL 31

LedDeviceAPA102_ftdi::LedDeviceAPA102_ftdi(const QJsonObject &deviceConfig) : ProviderFtdi(deviceConfig)
{
}

LedDevice *LedDeviceAPA102_ftdi::construct(const QJsonObject &deviceConfig)
{
return new LedDeviceAPA102_ftdi(deviceConfig);
}

bool LedDeviceAPA102_ftdi::init(const QJsonObject &deviceConfig)
{
bool isInitOK = false;

// Initialise sub-class
if (ProviderFtdi::init(deviceConfig))
{
_brightnessControlMaxLevel = deviceConfig["brightnessControlMaxLevel"].toInt(LED_BRIGHTNESS_FULL);
Info(_log, "[%s] Setting maximum brightness to [%d] = %d%%", QSTRING_CSTR(_activeDeviceType), _brightnessControlMaxLevel, _brightnessControlMaxLevel * 100 / LED_BRIGHTNESS_FULL);

CreateHeader();
isInitOK = true;
}
return isInitOK;
}

void LedDeviceAPA102_ftdi::CreateHeader()
{
const unsigned int startFrameSize = 4;
// Endframe, add additional 4 bytes to cover SK9922 Reset frame (in case SK9922 were sold as AP102) - has no effect on APA102
const unsigned int endFrameSize = (_ledCount / 32) * 4 + 4;
const unsigned int APAbufferSize = (_ledCount * 4) + startFrameSize + endFrameSize;
_ledBuffer.resize(APAbufferSize, 0);
Debug(_log, "APA102 buffer created. Led's number: %d", _ledCount);
}

int LedDeviceAPA102_ftdi::write(const std::vector<ColorRgb> &ledValues)
{
for (signed iLed = 0; iLed < static_cast<int>(_ledCount); ++iLed)
{
const ColorRgb &rgb = ledValues[iLed];
_ledBuffer[4 + iLed * 4 + 0] = LED_HEADER | _brightnessControlMaxLevel;
_ledBuffer[4 + iLed * 4 + 1] = rgb.red;
_ledBuffer[4 + iLed * 4 + 2] = rgb.green;
_ledBuffer[4 + iLed * 4 + 3] = rgb.blue;
}

return writeBytes(_ledBuffer.size(), _ledBuffer.data());
}
50 changes: 50 additions & 0 deletions sources/leddevice/dev_ftdi/LedDeviceAPA102_ftdi.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#ifndef LEDEVICET_APA102_H
#define LEDEVICET_APA102_H
#include "ProviderFtdi.h"

class LedDeviceAPA102_ftdi : public ProviderFtdi
{
Q_OBJECT

public:

///
/// @brief Constructs an APA102 LED-device
///
/// @param deviceConfig Device's configuration as JSON-Object
///
explicit LedDeviceAPA102_ftdi(const QJsonObject& deviceConfig);

///
/// @brief Constructs the LED-device
///
/// @param[in] deviceConfig Device's configuration as JSON-Object
/// @return LedDevice constructed
static LedDevice* construct(const QJsonObject& deviceConfig);

private:

///
/// @brief Initialise the device's configuration
///
/// @param[in] deviceConfig the JSON device configuration
/// @return True, if success
///
bool init(const QJsonObject& deviceConfig) override;

void CreateHeader();

///
/// @brief Writes the RGB-Color values to the LEDs.
///
/// @param[in] ledValues The RGB-color per LED
/// @return Zero on success, else negative
///
int write(const std::vector<ColorRgb>& ledValues) override;

/// The brighness level. Possibile values 1 .. 31.
int _brightnessControlMaxLevel;

};

#endif // LEDEVICET_APA102_H
Loading

0 comments on commit b7eb508

Please sign in to comment.