QList <DMXUSBWidget*> QLCFTDI::widgets()
{
    QList <DMXUSBWidget*> widgetList;
    quint32 input_id = 0;

    struct ftdi_context ftdi;

    ftdi_init(&ftdi);

#ifdef LIBFTDI1
    libusb_device *dev;
    libusb_device **devs;
    int i = 0;

    if (libusb_get_device_list(ftdi->usb_ctx, &devs) < 0)
    {
        qDebug() << "usb_find_devices() failed";
        ftdi_error_return(-5, "libusb_get_device_list() failed");
    }

    while ((dev = devs[i++]) != NULL)
    {
#else
    struct usb_bus *bus;
    struct usb_device *dev;

    usb_init();

    if (usb_find_busses() < 0)
    {
        qDebug() << "usb_find_busses() failed";
        return widgetList;
    }
    if (usb_find_devices() < 0)
    {
        qDebug() << "usb_find_devices() failed";
        return widgetList;
    }

    for (bus = usb_get_busses(); bus; bus = bus->next)
    {
      for (dev = bus->devices; dev; dev = dev->next)
      {
#endif
        Q_ASSERT(dev != NULL);

        // Skip non wanted devices
        if (dev->descriptor.idVendor != QLCFTDI::FTDIVID &&
            dev->descriptor.idVendor != QLCFTDI::ATMELVID)
                continue;

        if (dev->descriptor.idProduct != QLCFTDI::FTDIPID &&
            dev->descriptor.idProduct != QLCFTDI::DMX4ALLPID &&
            dev->descriptor.idProduct != QLCFTDI::NANODMXPID)
                continue;

        char ser[256];
        char nme[256];
        char vend[256];

        ftdi_usb_get_strings(&ftdi, dev, vend, 256, nme, 256, ser, 256);

        QString serial(ser);
        QString name(nme);
        QString vendor(vend);

        QMap <QString,QVariant> types(typeMap());

        qDebug() << Q_FUNC_INFO << "DMX USB VID:" << QString::number(dev->descriptor.idVendor, 16) <<
                    "PID:" << QString::number(dev->descriptor.idProduct, 16);
        qDebug() << Q_FUNC_INFO << "DMX USB serial: " << serial << "name:" << name << "vendor:" << vendor;

        if (types.contains(serial) == true)
        {
            // Force a widget with a specific serial to either type
            DMXUSBWidget::Type type = (DMXUSBWidget::Type) types[serial].toInt();
            switch (type)
            {
            case DMXUSBWidget::OpenTX:
                widgetList << new EnttecDMXUSBOpen(serial, name, vendor);
                break;
            case DMXUSBWidget::ProRX:
            {
                EnttecDMXUSBProRX* prorx = new EnttecDMXUSBProRX(serial, name, vendor, input_id++);
                widgetList << prorx;
                break;
            }
            case DMXUSBWidget::ProMk2:
            {
                EnttecDMXUSBProTX* protx = new EnttecDMXUSBProTX(serial, name, vendor, 1);
                widgetList << protx;
                widgetList << new EnttecDMXUSBProTX(serial, name, vendor, 2, protx->ftdi());
                EnttecDMXUSBProRX* prorx = new EnttecDMXUSBProRX(serial, name, vendor, input_id++, protx->ftdi());
                widgetList << prorx;
                break;
            }
            case DMXUSBWidget::UltraProTx:
            {
                UltraDMXUSBProTx* protx = new UltraDMXUSBProTx(serial, name, vendor, 1);
                widgetList << protx;
                widgetList << new UltraDMXUSBProTx(serial, name, vendor, 2, protx->ftdi());
                EnttecDMXUSBProRX* prorx = new EnttecDMXUSBProRX(serial, name, vendor, input_id++, protx->ftdi());
                widgetList << prorx;
                break;
            }
            case DMXUSBWidget::VinceTX:
                widgetList << new VinceUSBDMX512TX(serial, name, vendor);
                break;
            default:
            case DMXUSBWidget::ProTX:
                widgetList << new EnttecDMXUSBProTX(serial, name, vendor);
                break;
            }
        }
        else if (name.toUpper().contains("PRO MK2") == true)
        {
            EnttecDMXUSBProTX* protx = new EnttecDMXUSBProTX(serial, name, vendor, 1);
            widgetList << protx;
            widgetList << new EnttecDMXUSBProTX(serial, name, vendor, 2, protx->ftdi());
            EnttecDMXUSBProRX* prorx = new EnttecDMXUSBProRX(serial, name, vendor, input_id++, protx->ftdi());
            widgetList << prorx;
        }
        else if (name.toUpper().contains("DMX USB PRO"))
        {
            /** Check if the device responds to label 77 and 78, so it might be a DMXking adapter */
            int ESTAID = 0;
            int DEVID = 0;
            QString manName = readLabel(&ftdi, name.toLatin1().data(), serial.toLatin1().data(),
                                        USB_DEVICE_MANUFACTURER, &ESTAID);
            qDebug() << "--------> Device Manufacturer: " << manName;
            QString devName = readLabel(&ftdi, name.toLatin1().data(), serial.toLatin1().data(),
                                        USB_DEVICE_NAME, &DEVID);
            qDebug() << "--------> Device Name: " << devName;
            qDebug() << "--------> ESTA Code: " << QString::number(ESTAID, 16) << ", Device ID: " << QString::number(DEVID, 16);
            if (ESTAID == DMXKING_ESTA_ID)
            {
                if (DEVID == ULTRADMX_PRO_DEV_ID)
                {
                    UltraDMXUSBProTx* protxP1 = new UltraDMXUSBProTx(serial, name, vendor, 1);
                    protxP1->setRealName(devName);
                    widgetList << protxP1;
                    UltraDMXUSBProTx* protxP2 = new UltraDMXUSBProTx(serial, name, vendor, 2, protxP1->ftdi());
                    protxP2->setRealName(devName);
                    widgetList << protxP2;
                    EnttecDMXUSBProRX* prorx = new EnttecDMXUSBProRX(serial, name, vendor, input_id++, protxP1->ftdi());
                    prorx->setRealName(devName);
                    widgetList << prorx;
                }
                else
                {
                    EnttecDMXUSBProTX* protx = new EnttecDMXUSBProTX(serial, name, vendor);
                    protx->setRealName(devName);
                    widgetList << protx;
                }
            }
            else
            {
                /* This is probably a Enttec DMX USB Pro widget */
                EnttecDMXUSBProTX* protx = new EnttecDMXUSBProTX(serial, name, vendor);
                widgetList << protx;
                EnttecDMXUSBProRX* prorx = new EnttecDMXUSBProRX(serial, name, vendor, input_id++, protx->ftdi());
                widgetList << prorx;
            }
        }
        else if (name.toUpper().contains("USB-DMX512 CONVERTER") == true)
        {
            widgetList << new VinceUSBDMX512TX(serial, name, vendor);
        }
        else if (dev->descriptor.idVendor == QLCFTDI::FTDIVID &&
                 dev->descriptor.idProduct == QLCFTDI::DMX4ALLPID)
        {
            widgetList << new Stageprofi(serial, name, vendor);
        }
#if defined(Q_WS_X11) || defined(Q_OS_LINUX)
        else if (dev->descriptor.idVendor == QLCFTDI::ATMELVID &&
                 dev->descriptor.idProduct == QLCFTDI::NANODMXPID)
        {
            widgetList << new NanoDMX(serial, name, vendor);
        }
#endif
        else
        {
            /* This is probably an Open DMX USB widget */
            widgetList << new EnttecDMXUSBOpen(serial, name, vendor, 0);
        }
#ifndef LIBFTDI1
      }
#endif
    }

#ifdef LIBFTDI1
    libusb_free_device_list(devs, 1);
#endif

    ftdi_deinit(&ftdi);
    return widgetList;
}

bool QLCFTDI::open()
{
    if (m_openCount < m_refCount)
        m_openCount++;

    if (isOpen() == true)
        return true;

    if (ftdi_usb_open_desc(&m_handle, QLCFTDI::FTDIVID, QLCFTDI::FTDIPID,
                           name().toLatin1(), serial().toLatin1()) < 0)
    {
        qWarning() << Q_FUNC_INFO << name() << ftdi_get_error_string(&m_handle);
        return false;
    }
    else
    {
        return true;
    }
}

bool QLCFTDI::openByPID(const int PID)
{
    if (m_openCount < m_refCount)
        m_openCount++;

    if (isOpen() == true)
        return true;

    if (ftdi_usb_open(&m_handle, QLCFTDI::FTDIVID, PID) < 0)
    {
        qWarning() << Q_FUNC_INFO << name() << ftdi_get_error_string(&m_handle);
        return false;
    }
    else
    {
        return true;
    }
}

bool QLCFTDI::close()
{
    if (m_openCount > 1)
    {
        m_openCount--;
        return true;
    }

    if (ftdi_usb_close(&m_handle) < 0)
    {
        qWarning() << Q_FUNC_INFO << name() << ftdi_get_error_string(&m_handle);
        return false;
    }
    else
    {
        return true;
    }
}

bool QLCFTDI::isOpen() const
{
    return (m_handle.usb_dev != NULL) ? true : false;
}

bool QLCFTDI::reset()
{
    if (ftdi_usb_reset(&m_handle) < 0)
    {
        qWarning() << Q_FUNC_INFO << name() << ftdi_get_error_string(&m_handle);
        return false;
    }
    else
    {
        return true;
    }
}

bool QLCFTDI::setLineProperties()
{
    if (ftdi_set_line_property(&m_handle, BITS_8, STOP_BIT_2, NONE) < 0)
    {
        qWarning() << Q_FUNC_INFO << name() << ftdi_get_error_string(&m_handle);
        return false;
    }
    else
    {
        return true;
    }
}

bool QLCFTDI::setBaudRate()
{
    if (ftdi_set_baudrate(&m_handle, 250000) < 0)
    {
        qWarning() << Q_FUNC_INFO << name() << ftdi_get_error_string(&m_handle);
        return false;
    }
    else
    {
        return true;
    }
}

bool QLCFTDI::setFlowControl()
{
    if (ftdi_setflowctrl(&m_handle, SIO_DISABLE_FLOW_CTRL) < 0)
    {
        qWarning() << Q_FUNC_INFO << name() << ftdi_get_error_string(&m_handle);
        return false;
    }
    else
    {
        return true;
    }
}

bool QLCFTDI::clearRts()
{
    if (ftdi_setrts(&m_handle, 0) < 0)
    {
        qWarning() << Q_FUNC_INFO << name() << ftdi_get_error_string(&m_handle);
        return false;
    }
    else
    {
        return true;
    }
}

bool QLCFTDI::purgeBuffers()
{
    if (ftdi_usb_purge_buffers(&m_handle) < 0)
    {
        qWarning() << Q_FUNC_INFO << name() << ftdi_get_error_string(&m_handle);
        return false;
    }
    else
    {
        return true;
    }
}

bool QLCFTDI::setBreak(bool on)
{
    ftdi_break_type type;
    if (on == true)
        type = BREAK_ON;
    else
        type = BREAK_OFF;

    if (ftdi_set_line_property2(&m_handle, BITS_8, STOP_BIT_2, NONE, type) < 0)
    {
        qWarning() << Q_FUNC_INFO << name() << ftdi_get_error_string(&m_handle);
        return false;
    }
    else
    {
        return true;
    }
}
QList <DMXUSBWidget*> QLCFTDI::widgets()
{
    QList <DMXUSBWidget*> widgetList;
    quint32 input_id = 0;

    struct ftdi_device_list* list = 0;
    struct ftdi_context ftdi;
    ftdi_init(&ftdi);
    ftdi_usb_find_all(&ftdi, &list, QLCFTDI::VID, QLCFTDI::PID);
    while (list != NULL)
    {
#ifdef LIBFTDI1
        struct libusb_device* dev = list->dev;
#else
        struct usb_device* dev = list->dev;
#endif
        Q_ASSERT(dev != NULL);

        char serial[256];
        char name[256];
        char vendor[256];

        ftdi_usb_get_strings(&ftdi, dev,
                             vendor, sizeof(vendor),
                             name, sizeof(name),
                             serial, sizeof(serial));

        QString ser(serial);
        QString nme(name);
        QString ven(vendor);
        QMap <QString,QVariant> types(typeMap());

        qDebug() << "serial: " << ser << "name:" << nme << "vendor:" << ven;

        if (types.contains(ser) == true)
        {
            // Force a widget with a specific serial to either type
            DMXUSBWidget::Type type = (DMXUSBWidget::Type) types[ser].toInt();
            switch (type)
            {
            case DMXUSBWidget::OpenTX:
                widgetList << new EnttecDMXUSBOpen(serial, name, vendor);
                break;
            case DMXUSBWidget::ProRX:
            {
                EnttecDMXUSBProRX* prorx = new EnttecDMXUSBProRX(serial, name, vendor, input_id++);
                widgetList << prorx;
                break;
            }
            case DMXUSBWidget::ProMk2:
            {
                EnttecDMXUSBProTX* protx = new EnttecDMXUSBProTX(serial, name, vendor, 1);
                widgetList << protx;
                widgetList << new EnttecDMXUSBProTX(serial, name, vendor, 2, protx->ftdi());
                EnttecDMXUSBProRX* prorx = new EnttecDMXUSBProRX(serial, name, vendor, input_id++, protx->ftdi());
                widgetList << prorx;
                break;
            }
            case DMXUSBWidget::UltraProTx:
            {
                UltraDMXUSBProTx* protx = new UltraDMXUSBProTx(serial, name, vendor, 1);
                widgetList << protx;
                widgetList << new UltraDMXUSBProTx(serial, name, vendor, 2, protx->ftdi());
                EnttecDMXUSBProRX* prorx = new EnttecDMXUSBProRX(serial, name, vendor, input_id++, protx->ftdi());
                widgetList << prorx;
                break;
            }
            case DMXUSBWidget::VinceTX:
                widgetList << new VinceUSBDMX512TX(serial, name, vendor);
                break;
            default:
            case DMXUSBWidget::ProTX:
                widgetList << new EnttecDMXUSBProTX(serial, name, vendor);
                break;
            }
        }
        else if (nme.toUpper().contains("PRO MK2") == true)
        {
            EnttecDMXUSBProTX* protx = new EnttecDMXUSBProTX(serial, name, vendor, 1);
            widgetList << protx;
            widgetList << new EnttecDMXUSBProTX(serial, name, vendor, 2, protx->ftdi());
            EnttecDMXUSBProRX* prorx = new EnttecDMXUSBProRX(serial, name, vendor, input_id++, protx->ftdi());
            widgetList << prorx;
        }
        else if (nme.toUpper().contains("DMX USB PRO"))
        {
            /** Check if the device responds to label 77 and 78, so it might be a DMXking adapter */
            int ESTAID = 0;
            int DEVID = 0;
            QString manName = readLabel(&ftdi, name, serial, USB_DEVICE_MANUFACTURER, &ESTAID);
            qDebug() << "--------> Device Manufacturer: " << manName;
            QString devName = readLabel(&ftdi, name, serial, USB_DEVICE_NAME, &DEVID);
            qDebug() << "--------> Device Name: " << devName;
            qDebug() << "--------> ESTA Code: " << QString::number(ESTAID, 16) << ", Device ID: " << QString::number(DEVID, 16);
            if (ESTAID == DMXKING_ESTA_ID)
            {
                if (DEVID == ULTRADMX_PRO_DEV_ID)
                {
                    UltraDMXUSBProTx* protxP1 = new UltraDMXUSBProTx(serial, name, vendor, 1);
                    protxP1->setRealName(devName);
                    widgetList << protxP1;
                    UltraDMXUSBProTx* protxP2 = new UltraDMXUSBProTx(serial, name, vendor, 2, protxP1->ftdi());
                    protxP2->setRealName(devName);
                    widgetList << protxP2;
                    EnttecDMXUSBProRX* prorx = new EnttecDMXUSBProRX(serial, name, vendor, input_id++, protxP1->ftdi());
                    prorx->setRealName(devName);
                    widgetList << prorx;
                }
                else
                {
                    EnttecDMXUSBProTX* protx = new EnttecDMXUSBProTX(serial, name, vendor);
                    protx->setRealName(devName);
                    widgetList << protx;
                }
            }
            else
            {
                /* This is probably a Enttec DMX USB Pro widget */
                EnttecDMXUSBProTX* protx = new EnttecDMXUSBProTX(serial, name, vendor);
                widgetList << protx;
                EnttecDMXUSBProRX* prorx = new EnttecDMXUSBProRX(serial, name, vendor, input_id++, protx->ftdi());
                widgetList << prorx;
            }
        }
        else if (nme.toUpper().contains("USB-DMX512 CONVERTER") == true)
        {
            widgetList << new VinceUSBDMX512TX(serial, name, vendor);
        }
        else
        {
            /* This is probably an Open DMX USB widget */
            widgetList << new EnttecDMXUSBOpen(serial, name, vendor, 0);
        }

        list = list->next;
    }

    /* Search for DMX4ALL devices now */
    ftdi_usb_find_all(&ftdi, &list, QLCFTDI::VID, QLCFTDI::DMX4ALLPID);
    while (list != NULL)
    {
#ifdef LIBFTDI1
        struct libusb_device* dev = list->dev;
#else
        struct usb_device* dev = list->dev;
#endif
        Q_ASSERT(dev != NULL);

        char serial[256];
        char name[256];
        char vendor[256];

        ftdi_usb_get_strings(&ftdi, dev,
                             vendor, sizeof(vendor),
                             name, sizeof(name),
                             serial, sizeof(serial));

        QString ser(serial);
        QString nme(name);
        QString ven(vendor);

        qDebug() << "serial: " << ser << "name:" << nme << "vendor:" << ven;
        widgetList << new DMX4ALL(ser, nme, ven);

        list = list->next;
    }

    ftdi_deinit(&ftdi);
    return widgetList;
}