From 349bbadd8e66f13afc74a91b1df35cf216c05ce3 Mon Sep 17 00:00:00 2001 From: LordGrey Date: Sun, 2 Apr 2023 12:55:27 +0000 Subject: [PATCH] Support addressing device via SerialNumber and handle add more error handlingin discovery --- assets/webconfig/js/content_leds.js | 88 +++++++++++++++++++-- libsrc/leddevice/dev_ftdi/ProviderFtdi.cpp | 90 +++++++++++++++------- 2 files changed, 142 insertions(+), 36 deletions(-) diff --git a/assets/webconfig/js/content_leds.js b/assets/webconfig/js/content_leds.js index 5b0c84e9..efcf1c6e 100755 --- a/assets/webconfig/js/content_leds.js +++ b/assets/webconfig/js/content_leds.js @@ -19,6 +19,7 @@ var bottomLeft2topLeft = null; var toggleKeystoneCorrectionArea = false; var devRPiSPI = ['apa102', 'apa104', 'ws2801', 'lpd6803', 'lpd8806', 'p9813', 'sk6812spi', 'sk6822spi', 'sk9822', 'ws2812spi']; +var devFTDI = ['apa102_ftdi', 'sk6812_ftdi', 'ws2812_ftdi']; var devRPiPWM = ['ws281x']; var devRPiGPIO = ['piblaster']; var devNET = ['atmoorb', 'cololight', 'fadecandy', 'philipshue', 'nanoleaf', 'razer', 'tinkerforge', 'tpm2net', 'udpe131', 'udpartnet', 'udpddp', 'udph801', 'udpraw', 'wled', 'yeelight']; @@ -1119,9 +1120,12 @@ $(document).ready(function () { case "karate": case "sedu": case "tpm2": - case "ws2812_ftdi": - case "sk6812_ftdi": + + //FTDI devices case "apa102_ftdi": + case "sk6812_ftdi": + case "ws2812_ftdi": + if (storedAccess === 'expert') { filter.discoverAll = true; } @@ -1142,7 +1146,16 @@ $(document).ready(function () { }); hwLedCountDefault = 1; - colorOrderDefault = "rgb"; + + switch (ledType) { + case "sk6812spi": + case "sk6812_ftdi": + colorOrderDefault = "grb"; + break; + default: + colorOrderDefault = "rgb"; + } + break; case "philipshue": @@ -1425,6 +1438,9 @@ $(document).ready(function () { case "sk9822": case "ws2812spi": case "piblaster": + case "apa102_ftdi": + case "sk6812_ftdi": + case "ws2812_ftdi": default: } @@ -1856,6 +1872,9 @@ function saveLedConfig(genDefLayout = false) { case "sk9822": case "ws2812spi": case "piblaster": + case "apa102_ftdi": + case "sk6812_ftdi": + case "ws2812_ftdi": default: if (genDefLayout === true) { ledConfig = { @@ -1906,10 +1925,12 @@ var updateOutputSelectList = function (ledType, discoveryInfo) { if ($.inArray(ledType, devNET) != -1) { ledTypeGroup = "devNET"; - } else if ($.inArray(ledType, devSerial) != -1 || ledType.endsWith("_ftdi")) { + } else if ($.inArray(ledType, devSerial) != -1) { ledTypeGroup = "devSerial"; } else if ($.inArray(ledType, devRPiSPI) != -1) { ledTypeGroup = "devRPiSPI"; + } else if ($.inArray(ledType, devFTDI) != -1) { + ledTypeGroup = "devFTDI"; } else if ($.inArray(ledType, devRPiGPIO) != -1) { ledTypeGroup = "devRPiGPIO"; } else if ($.inArray(ledType, devRPiPWM) != -1) { @@ -2003,9 +2024,6 @@ var updateOutputSelectList = function (ledType, discoveryInfo) { case "karate": case "sedu": case "tpm2": - case "ws2812_ftdi": - case "sk6812_ftdi": - case "apa102_ftdi": for (const device of discoveryInfo.devices) { if (device.udev) { enumVals.push(device.systemLocation); @@ -2035,6 +2053,62 @@ var updateOutputSelectList = function (ledType, discoveryInfo) { } } break; + + case "devFTDI": + key = "output"; + + if (discoveryInfo.devices.length == 0) { + enumVals.push("NONE"); + enumTitleVals.push($.i18n('edt_dev_spec_devices_discovered_none')); + $('#btn_submit_controller').prop('disabled', true); + showAllDeviceInputOptions(key, false); + } + else { + switch (ledType) { + case "ws2812_ftdi": + case "sk6812_ftdi": + case "apa102_ftdi": + for (const device of discoveryInfo.devices) { + enumVals.push(device.ftdiOpenString); + + var title = "FTDI"; + if (device.manufacturer) { + title = device.manufacturer + } + + if (device.serialNumber) { + title += " - " + device.serialNumber; + } + title += " (" + device.vendorIdentifier + "|" + device.productIdentifier + ")"; + + if (device.description) { + title += " " + device.description; + } + + enumTitleVals.push(title); + } + + // Select configured device + var configuredDeviceType = window.serverConfig.device.type; + var configuredOutput = window.serverConfig.device.output; + if (ledType === configuredDeviceType) { + if ($.inArray(configuredOutput, enumVals) != -1) { + enumDefaultVal = configuredOutput; + } else { + enumVals.push(window.serverConfig.device.output); + enumDefaultVal = configuredOutput; + } + } + else { + addSelect = true; + } + + break; + default: + } + } + break; + case "devRPiSPI": case "devRPiGPIO": key = "output"; diff --git a/libsrc/leddevice/dev_ftdi/ProviderFtdi.cpp b/libsrc/leddevice/dev_ftdi/ProviderFtdi.cpp index c5088097..2463f8d3 100644 --- a/libsrc/leddevice/dev_ftdi/ProviderFtdi.cpp +++ b/libsrc/leddevice/dev_ftdi/ProviderFtdi.cpp @@ -11,7 +11,7 @@ namespace Pin { - // enumerate the AD bus for conveniance. + // enumerate the AD bus for convenience. enum bus_t { SK = 0x01, // ADBUS0, SPI data clock @@ -28,7 +28,7 @@ const QString ProviderFtdi::AUTO_SETTING = QString("auto"); ProviderFtdi::ProviderFtdi(const QJsonObject &deviceConfig) : LedDevice(deviceConfig), - _ftdic(NULL), + _ftdic(nullptr), _baudRate_Hz(1000000) { } @@ -90,7 +90,7 @@ int ProviderFtdi::open() double reference_clock = 60e6; int divisor = (reference_clock / 2 / _baudRate_Hz) - 1; uint8_t buf[10] = {0}; - unsigned int icmd = 0; + int icmd = 0; buf[icmd++] = DIS_DIV_5; buf[icmd++] = TCK_DIVISOR; buf[icmd++] = divisor; @@ -110,13 +110,13 @@ int ProviderFtdi::open() int ProviderFtdi::close() { - if (_ftdic != NULL) + if (_ftdic != nullptr) { Debug(_log, "Closing FTDI device"); wait(15); // Delay to give time to push color black from writeBlack() into the led ftdi_set_bitmode(_ftdic, 0x00, BITMODE_RESET); ftdi_usb_close(_ftdic); - _ftdic = NULL; + _ftdic = nullptr; } return LedDevice::close(); } @@ -125,13 +125,13 @@ void ProviderFtdi::setInError(const QString &errorMsg, bool isRecoverable) { close(); - LedDevice::setInError(errorMsg); + LedDevice::setInError(errorMsg, isRecoverable); } int ProviderFtdi::writeBytes(const qint64 size, const uint8_t *data) { uint8_t buf[10] = {0}; - unsigned int icmd = 0; + int icmd = 0; int rc = 0; int count_arg = size - 1; @@ -176,35 +176,67 @@ QJsonObject ProviderFtdi::discover(const QJsonObject & /*params*/) if (ftdi_usb_find_all(ftdic, &devlist, ANY_FTDI_VENDOR, ANY_FTDI_PRODUCT) > 0) { struct ftdi_device_list *curdev = devlist; - QMap deviceIndexes; + QMap deviceIndexes; + while (curdev) { - char manufacturer[128], description[128]; - ftdi_usb_get_strings(ftdic, curdev->dev, manufacturer, 128, description, 128, NULL, 0); - libusb_device_descriptor desc; - libusb_get_device_descriptor(curdev->dev, &desc); + int rc = libusb_get_device_descriptor(curdev->dev, &desc); + if (rc == 0) + { + QString vendorIdentifier = QString("0x%1").arg(desc.idVendor, 4, 16, QChar{'0'}); + QString productIdentifier = QString("0x%1").arg(desc.idProduct, 4, 16, QChar{'0'}); + QString vendorAndProduct = QString("%1:%2") + .arg(vendorIdentifier) + .arg(productIdentifier); + uint8_t deviceIndex = deviceIndexes.value(vendorAndProduct, 0); - QString vendorIdentifier = QString("0x%1").arg(desc.idVendor, 4, 16, QChar{'0'}); - QString productIdentifier = QString("0x%1").arg(desc.idProduct, 4, 16, QChar{'0'}); - QString vendorAndProduct = QString("i:%1:%2") - .arg(vendorIdentifier) - .arg(productIdentifier); - uint8_t deviceIndex = deviceIndexes.value(vendorAndProduct, 0); + QString serialNumber; + char serial_string[128]; + rc = ftdi_usb_get_strings2(ftdic, curdev->dev, nullptr, 0, nullptr, 0, serial_string, 128); + if (rc == 0) + { + serialNumber = serial_string; + } - QString portName = QString("%1:%2").arg(vendorAndProduct).arg(deviceIndex); + QString ftdiOpenString; + if(!serialNumber.isEmpty()) + { + ftdiOpenString = QString("s:%1:%2").arg(vendorAndProduct).arg(serialNumber); + } + else + { + ftdiOpenString = QString("i:%1:%2").arg(vendorAndProduct).arg(deviceIndex); + } - deviceList.push_back(QJsonObject{ - {"portName", portName}, - {"vendorIdentifier", vendorIdentifier}, - {"productIdentifier", productIdentifier}, - {"manufacturer", manufacturer}, - {"description", description}, - }); + QString manufacturer; + char manufacturer_string[128]; + rc = ftdi_usb_get_strings2(ftdic, curdev->dev, manufacturer_string, 128, nullptr, 0, nullptr, 0); + if (rc == 0) + { + manufacturer = manufacturer_string; + } + QString description; + char description_string[128]; + rc = ftdi_usb_get_strings2(ftdic, curdev->dev, nullptr, 0, description_string, 128, nullptr, 0); + if (rc == 0) + { + description = description_string; + } + + deviceList.push_back(QJsonObject{ + {"ftdiOpenString", ftdiOpenString}, + {"vendorIdentifier", vendorIdentifier}, + {"productIdentifier", productIdentifier}, + {"deviceIndex", deviceIndex}, + {"serialNumber", serialNumber}, + {"manufacturer", manufacturer}, + {"description", description} + }); + deviceIndexes.insert(vendorAndProduct, deviceIndex + 1); + } curdev = curdev->next; - - deviceIndexes.insert(vendorAndProduct, deviceIndex + 1); } } @@ -217,4 +249,4 @@ QJsonObject ProviderFtdi::discover(const QJsonObject & /*params*/) Debug(_log, "FTDI devices discovered: [%s]", QString(QJsonDocument(devicesDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData()); return devicesDiscovered; -} \ No newline at end of file +}