• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mcallegari / qlcplus / 13633248611

03 Mar 2025 02:31PM UTC coverage: 31.871% (+0.4%) from 31.5%
13633248611

push

github

web-flow
actions: add chrpath to profile

14689 of 46089 relevant lines covered (31.87%)

26426.11 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/ui/src/rdmmanager.cpp
1
/*
2
  Q Light Controller Plus
3
  rdmmanager.cpp
4

5
  Copyright (c) Massimo Callegari
6

7
  Licensed under the Apache License Version 2.0 (the "License");
8
  you may not use this file except in compliance with the License.
9
  You may obtain a copy of the License at
10

11
      http://www.apache.org/licenses/LICENSE-2.0.txt
12

13
  Unless required by applicable law or agreed to in writing software
14
  distributed under the License is distributed on an "AS IS" BASIS
15
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND either express or implied.
16
  See the License for the specific language governing permissions and
17
  limitations under the License.
18
*/
19

20
#include <QDebug>
21
#include <QMessageBox>
22

23
#include "rdmmanager.h"
24
#include "outputpatch.h"
25
#include "qlcioplugin.h"
26
#include "rdmprotocol.h"
27
#include "doc.h"
28

29
// RDM view column numbers
30
#define KColumnRDMModel    0
31
#define KColumnRDMUniverse 1
32
#define KColumnRDMAddress  2
33
#define KColumnRDMChannels 3
34
#define KColumnRDMUID      4
35

36
#define MAX_WAIT_COUNT  30
37

38
RDMManager::RDMManager(QWidget *parent, Doc *doc)
×
39
    : QWidget(parent)
40
    , m_doc(doc)
×
41
{
42
    setupUi(this);
×
43

44
    m_getInfoButton->setEnabled(false);
×
45
    m_readButton->setEnabled(false);
×
46

47
    connect(m_refreshButton, SIGNAL(clicked()), this, SLOT(slotRefresh()));
×
48
    connect(m_getInfoButton, SIGNAL(clicked()), this, SLOT(slotGetInfo()));
×
49
    connect(m_rdmTree, SIGNAL(itemSelectionChanged()), this, SLOT(slotSelectionChanged()));
×
50
    connect(m_readButton, SIGNAL(clicked()), this, SLOT(slotReadPID()));
×
51
    connect(m_writeButton, SIGNAL(clicked()), this, SLOT(slotWritePID()));
×
52
}
×
53

54
RDMManager::~RDMManager()
×
55
{
56
}
×
57

58
void RDMManager::slotRefresh()
×
59
{
60
    m_refreshButton->setEnabled(false);
×
61

62
    // reset any previously collected information
63
    m_rdmTree->clear();
×
64

65
    m_devFoundLabel->setText("Discovering fixtures...");
×
66

67
    // go through every universe and launch a RDM discovery for each
68
    // patched plugin which supports the RDM standard
69
    foreach (Universe *uni, m_doc->inputOutputMap()->universes())
×
70
    {
71
        for (int i = 0; i < uni->outputPatchesCount(); i++)
×
72
        {
73
            OutputPatch *op = uni->outputPatch(i);
×
74
            if (op->plugin()->capabilities() & QLCIOPlugin::RDM)
×
75
            {
76
                RDMWorker *wt = new RDMWorker(m_doc);
×
77
                connect(wt, SIGNAL(uidFound(QString, UIDInfo)),
×
78
                        this, SLOT(updateRDMTreeItem(QString, UIDInfo)));
79
                connect(wt, SIGNAL(requestPopup(QString, QString)),
×
80
                        this, SLOT(slotDisplayPopup(QString, QString)));
81
                connect(wt, SIGNAL(finished()),
×
82
                        this, SLOT(slotTaskFinished()));
83
                wt->runDiscovery(uni->id(), op->output());
×
84
            }
85
        }
86
    }
87
}
×
88

89
bool RDMManager::getPluginInfo(quint32 universe, quint32 line, quint32 &universeID, quint32 &outputLine)
×
90
{
91
    Universe *uni = m_doc->inputOutputMap()->universe(universe);
×
92
    if (uni == NULL)
×
93
    {
94
        qDebug() << "ERROR. Universe not found!";
95
        return false;
96
    }
97

98
    OutputPatch *op = NULL;
99
    for (int i = 0; i < uni->outputPatchesCount(); i++)
×
100
    {
101
        op = uni->outputPatch(i);
×
102
        if (op->output() == line)
×
103
            break;
104
    }
105
    if (op == NULL)
×
106
    {
107
        qDebug() << "ERROR. Output patch not found!";
108
        return false;
109
    }
110

111
    universeID = uni->id();
×
112
    outputLine = op->output();
×
113

114
    return true;
×
115
}
116

117
void RDMManager::slotGetInfo()
×
118
{
119
    QTreeWidgetItem *item = m_rdmTree->selectedItems().first();
×
120
    QString UID = item->text(KColumnRDMUID);
×
121
    UIDInfo info = m_uidMap.value(UID);
×
122
    quint32 uniID = 0, outLine = 0;
×
123

124
    if (getPluginInfo(info.universe, info.pluginLine, uniID, outLine) == false)
×
125
    {
126
        qDebug() << "ERROR. Cannot get plugin info";
127
        return;
128
    }
129

130
    RDMWorker *wt = new RDMWorker(m_doc);
×
131
    connect(wt, SIGNAL(fixtureInfoReady(QString&)), this, SIGNAL(fixtureInfoReady(QString&)));
×
132
    connect(wt, SIGNAL(requestPopup(QString, QString)), this, SLOT(slotDisplayPopup(QString, QString)));
×
133
    wt->getUidInfo(uniID, outLine, UID, info);
×
134
}
×
135

136
void RDMManager::slotReadPID()
×
137
{
138
    QTreeWidgetItem *item = m_rdmTree->selectedItems().first();
×
139
    QString UID = item->text(KColumnRDMUID);
×
140
    UIDInfo info = m_uidMap.value(UID);
×
141
    quint32 uniID = 0, outLine = 0;
×
142
    QVariantList params;
143

144
    if (getPluginInfo(info.universe, info.pluginLine, uniID, outLine) == false)
×
145
    {
146
        qDebug() << "ERROR. Cannot get plugin info";
147
        return;
148
    }
149

150
    m_pidResult->clear();
×
151
    QString args = m_pidArgsEdit->text().toLower();
×
152
    bool ok;
153

154
    if (args.length())
×
155
    {
156
        switch(m_dataTypeCombo->currentIndex())
×
157
        {
158
            case ByteArg:
×
159
                params.append(uchar(1));
×
160
                if (args.startsWith("0x"))
×
161
                    params.append(uchar(args.mid(2).toUShort(&ok, 16)));
×
162
                else
163
                    params.append(uchar(args.toUShort()));
×
164
            break;
165
            case ShortArg:
×
166
                params.append(uchar(2));
×
167
                if (args.startsWith("0x"))
×
168
                    params.append(args.mid(2).toUShort(&ok, 16));
×
169
                else
170
                    params.append(args.toShort());
×
171
            break;
172
            case LongArg:
×
173
                params.append(uchar(4));
×
174
                if (args.startsWith("0x"))
×
175
                    params.append(quint32(args.mid(2).toULong(&ok, 16)));
×
176
                else
177
                    params.append(quint32(args.toULong()));
×
178
            break;
179
            case ArrayArg:
×
180
                params.append(uchar(99));
×
181
                foreach (QString arg, args.split(","))
×
182
                    params.append(uchar(arg.toUShort(&ok, 16)));
×
183
            break;
×
184
        }
185
    }
186

187
    RDMWorker *wt = new RDMWorker(m_doc);
×
188
    connect(wt, SIGNAL(requestPopup(QString, QString)), this, SLOT(slotDisplayPopup(QString, QString)));
×
189
    connect(wt, SIGNAL(pidInfoReady(QString)), this, SLOT(slotUpdatePidInfo(QString)));
×
190
    wt->handlePID(uniID, outLine, UID, m_pidEdit->text(), params, false);
×
191
}
×
192

193
void RDMManager::slotWritePID()
×
194
{
195
    QTreeWidgetItem *item = m_rdmTree->selectedItems().first();
×
196
    QString UID = item->text(KColumnRDMUID);
×
197
    UIDInfo info = m_uidMap.value(UID);
×
198
    quint32 uniID = 0, outLine = 0;
×
199
    QVariantList params;
200

201
    if (getPluginInfo(info.universe, info.pluginLine, uniID, outLine) == false)
×
202
    {
203
        qDebug() << "ERROR. Cannot get plugin info";
204
        return;
205
    }
206

207
    m_pidResult->clear();
×
208

209
    if (m_pidArgsEdit->text().length())
×
210
    {
211
        QStringList argList = m_pidArgsEdit->text().split(",");
×
212
        bool ok;
213

214
        if (m_dataTypeCombo->currentIndex() == ArrayArg)
×
215
        {
216
            QByteArray baArg;
217

218
            params.append(uchar(99)); // special size for array
×
219

220
            for (int i = 0; i < argList.count(); i++)
×
221
                baArg.append(QByteArray::fromHex(argList.at(i).toUtf8()));
×
222

223
            params.append(baArg);
×
224
        }
×
225
        else
226
        {
227
            for (int i = 0; i < argList.count(); i++)
×
228
            {
229
                QString arg = argList.at(i);
230

231
                switch(m_dataTypeCombo->currentIndex())
×
232
                {
233
                    case ByteArg:
×
234
                        params.append(uchar(1));
×
235
                        if (arg.toLower().startsWith("0x"))
×
236
                            params.append(uchar(arg.mid(2).toUShort(&ok, 16)));
×
237
                        else
238
                            params.append(uchar(arg.toUShort()));
×
239
                    break;
240
                    case ShortArg:
×
241
                        params.append(uchar(2));
×
242
                        if (arg.toLower().startsWith("0x"))
×
243
                            params.append(arg.mid(2).toShort(&ok, 16));
×
244
                        else
245
                            params.append(arg.toShort());
×
246
                    break;
247
                    case LongArg:
×
248
                        params.append(uchar(4));
×
249
                        if (arg.toLower().startsWith("0x"))
×
250
                            params.append(quint32(arg.mid(2).toULong(&ok, 16)));
×
251
                        else
252
                            params.append(quint32(arg.toULong()));
×
253
                    break;
254
                }
255
            }
×
256
        }
257
    }
258

259
    RDMWorker *wt = new RDMWorker(m_doc);
×
260
    connect(wt, SIGNAL(requestPopup(QString, QString)), this, SLOT(slotDisplayPopup(QString, QString)));
×
261
    connect(wt, SIGNAL(pidInfoReady(QString)), this, SLOT(slotUpdatePidInfo(QString)));
×
262
    wt->handlePID(uniID, outLine, UID, m_pidEdit->text(), params, true);
×
263
}
×
264

265
void RDMManager::slotSelectionChanged()
×
266
{
267
    int selectedCount = m_rdmTree->selectedItems().size();
×
268

269
    m_getInfoButton->setEnabled(selectedCount ? true : false);
×
270
    m_readButton->setEnabled(selectedCount ? true : false);
×
271
}
×
272

273
void RDMManager::slotUpdatePidInfo(QString info)
×
274
{
275
    m_pidResult->setText(info);
×
276
}
×
277

278
void RDMManager::slotDisplayPopup(QString title, QString message)
×
279
{
280
    QMessageBox::information(this, title, message);
×
281
    m_refreshButton->setEnabled(true);
×
282
}
×
283

284
void RDMManager::slotTaskFinished()
×
285
{
286
    m_refreshButton->setEnabled(true);
×
287
}
×
288

289
void RDMManager::updateRDMTreeItem(QString UID, UIDInfo info)
×
290
{
291
    QTreeWidgetItem *item = NULL;
292

293
    qDebug() << "Got info for UID" << UID;
294

295
    m_uidMap[UID] = info;
×
296

297
    for (int i = 0; i < m_rdmTree->topLevelItemCount(); i++)
×
298
    {
299
        QTreeWidgetItem *tlItem = m_rdmTree->topLevelItem(i);
×
300
        QString itemUID = tlItem->text(KColumnRDMUID);
×
301
        if (itemUID == UID)
×
302
        {
303
            item = tlItem;
304
            break;
305
        }
306
    }
×
307

308
    if (item == NULL)
×
309
    {
310
        item = new QTreeWidgetItem(m_rdmTree);
×
311
        item->setText(KColumnRDMUID, UID);
×
312
    }
313

314
    item->setText(KColumnRDMModel, QString ("%1 - %2").arg(info.manufacturer).arg(info.name));
×
315
    item->setText(KColumnRDMUniverse, QString::number(info.universe + 1));
×
316
    item->setText(KColumnRDMAddress,  QString::number(info.dmxAddress));
×
317
    item->setText(KColumnRDMChannels, QString::number(info.channels));
×
318

319
    m_rdmTree->header()->resizeSections(QHeaderView::ResizeToContents);
×
320

321
    if (m_rdmTree->topLevelItemCount())
×
322
        m_devFoundLabel->setText(QString("Fixtures found: %1").arg(m_rdmTree->topLevelItemCount()));
×
323
    else
324
        m_devFoundLabel->setText("No fixtures found");
×
325
}
×
326

327
/************************************************************************
328
 * RDM worker implementation
329
 ************************************************************************/
330

331
RDMWorker::RDMWorker(Doc *doc)
×
332
    : m_doc(doc)
×
333
    , m_running(false)
×
334
    , m_requestState(StateNone)
×
335
{
336
}
×
337

338
RDMWorker::~RDMWorker()
×
339
{
340
    stop();
×
341
}
×
342

343
void RDMWorker::runDiscovery(quint32 uni, quint32 line)
×
344
{
345
    m_universe = uni;
×
346
    m_line = line;
×
347

348
    DiscoveryInfo info;
349
    info.startUID = 0;
×
350
    info.endUID = (qulonglong(BROADCAST_ESTA_ID) << 32) + qulonglong(BROADCAST_DEVICE_ID);
×
351
    m_discoveryList.append(info);
×
352

353
    m_requestState = StateDiscoveryStart;
×
354
    start();
×
355
}
×
356

357
void RDMWorker::getUidInfo(quint32 uni, quint32 line, QString UID, UIDInfo &info)
×
358
{
359
    m_universe = uni;
×
360
    m_line = line;
×
361
    m_uidMap[UID] = info;
×
362

363
    QPalette pal;
×
364
    QColor hlBack(pal.color(QPalette::Highlight));
365
    QColor hlText(pal.color(QPalette::HighlightedText));
366

367
    // initialize the fixture information
368
    m_fixtureInfo = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">";
×
369
    m_fixtureInfo += "<HTML><HEAD></HEAD><STYLE>";
×
370
    m_fixtureInfo += QString(".hilite {" \
×
371
                             "        background-color: %1;" \
372
                             "        color: %2;" \
373
                             "        font-size: x-large;" \
374
                             "}").arg(hlBack.name()).arg(hlText.name());
×
375
    m_fixtureInfo += QString(".subhi {" \
×
376
                             "        background-color: %1;" \
377
                             "        color: %2;" \
378
                             "        font-weight: bold;" \
379
                             "}").arg(hlBack.name()).arg(hlText.name());
×
380
    m_fixtureInfo += QString(".emphasis {" \
×
381
                             "        font-weight: bold;" \
382
                             "}");
383
    m_fixtureInfo += QString(".tiny {"\
×
384
                             "   font-size: small;" \
385
                             "}");
386
    m_fixtureInfo += "</STYLE>";
×
387

388
    QString title("<TR CLASS='hilite'><TD COLSPAN='2'>%1</TD><TD COLSPAN='2' ALIGN='right'>UID: %3</TD></TR>");
×
389
    QString genInfo("<TR><TD CLASS='emphasis'>%1</TD><TD COLSPAN='3'>%2</TD></TR>");
×
390

391
    /********************************************************************
392
     * General info
393
     ********************************************************************/
394

395
    m_fixtureInfo += "<TABLE COLS='4' WIDTH='100%'>";
×
396

397
    // Fixture title
398
    m_fixtureInfo += title.arg(info.name).arg(UID);
×
399

400
    // Manufacturer
401
    m_fixtureInfo += genInfo.arg(tr("Manufacturer")).arg(info.manufacturer);
×
402
    m_fixtureInfo += genInfo.arg(tr("Model")).arg(info.name);
×
403
    //info += genInfo.arg(tr("Mode")).arg(m_fixtureMode->name());
404
    m_fixtureInfo += genInfo.arg(tr("Type")).arg(info.params.value("TYPE").toString());
×
405

406
    // Universe
407
    m_fixtureInfo += genInfo.arg(tr("Universe")).arg(info.universe + 1);
×
408

409
    // Address
410
    QString range = QString("%1 - %2").arg(info.dmxAddress).arg(info.dmxAddress + info.channels);
×
411
    m_fixtureInfo += genInfo.arg(tr("Address Range")).arg(range);
×
412

413
    // Channels
414
    m_fixtureInfo += genInfo.arg(tr("Channels")).arg(info.channels);
×
415

416
    QString header("<TR CLASS='hilite'><TD COLSPAN='4'>%1</TD></TR>");
×
417
    m_fixtureInfo += header.arg(tr("Personalities"));
×
418

419
    m_requestState = StatePersonalities;
×
420
    start();
×
421
}
×
422

423
void RDMWorker::handlePID(quint32 uni, quint32 line, QString UID, QString pid, QVariantList args, bool write)
×
424
{
425
    m_universe = uni;
×
426
    m_line = line;
×
427
    UIDInfo info;
428
    bool ok;
429

430
    if (pid.toLower().startsWith("0x"))
×
431
        info.dmxAddress = pid.mid(2).toUInt(&ok, 16);
×
432
    else
433
        info.dmxAddress = pid.toUInt(&ok, 10);
×
434

435
    if (ok == false)
×
436
    {
437
        emit requestPopup("Error", "Invalid PID entered!");
×
438
        return;
439
    }
440

441
    if (args.length())
×
442
    {
443
        for (int i = 0; i < args.count(); i++)
×
444
            info.params.insert(QString::number(i), args.at(i));
×
445
    }
446

447
    m_uidMap[UID] = info;
×
448

449
    if (write)
×
450
        m_requestState = StateWriteSinglePid;
×
451
    else
452
        m_requestState = StateReadSinglePid;
×
453

454
    start();
×
455
}
×
456

457
void RDMWorker::run()
×
458
{
459
    int waitCount = 0;
460

461
    Universe *uni = m_doc->inputOutputMap()->universe(m_universe);
×
462
    if (uni == NULL)
×
463
    {
464
        qDebug() << "ERROR. Universe not found!";
465
        return;
466
    }
467

468
    OutputPatch *op = NULL;
469
    for (int i = 0; i < uni->outputPatchesCount(); i++)
×
470
    {
471
        op = uni->outputPatch(i);
×
472
        if (op->output() == m_line)
×
473
            break;
474
    }
475
    if (op == NULL)
×
476
    {
477
        qDebug() << "ERROR. Output patch not found!";
478
        return;
479
    }
480
    m_plugin = op->plugin();
×
481

482
    connect(m_plugin, SIGNAL(rdmValueChanged(quint32, quint32, QVariantMap)),
×
483
            this, SLOT(slotRDMDataReady(quint32, quint32, QVariantMap)));
484

485
    m_running = true;
×
486
    while (m_running == true)
×
487
    {
488
        switch (m_requestState)
×
489
        {
490
            case StateNone:
×
491
            {
492
                // Nothing to do. Terminate the thread
493
                m_running = false;
×
494
            }
495
            break;
×
496
            case StateDiscoveryStart:
×
497
            {
498
                m_requestState = StateDiscoveryContinue;
×
499
                //m_plugin->sendRDMCommand(m_universe, m_line, DISCOVERY_COMMAND,
500
                //                         QVariantList() << RDMProtocol::broadcastAddress() << PID_DISC_UN_MUTE);
501
            }
502
            break;
×
503
            case StateDiscoveryContinue:
×
504
            {
505
                waitCount = 0;
506

507
                if (m_discoveryList.isEmpty())
×
508
                {
509
                    m_requestState = StateDiscoveryEnd;
×
510
                    break;
511
                }
512

513
                DiscoveryInfo info = m_discoveryList.first();
×
514
                qDebug() << "Discovery - CONTINUE between" << QString::number(info.startUID, 16)
515
                         << "and" << QString::number(info.endUID, 16);
516
                m_plugin->sendRDMCommand(m_universe, m_line, DISCOVERY_COMMAND,
×
517
                                         QVariantList() << RDMProtocol::broadcastAddress()
×
518
                                                        << PID_DISC_UNIQUE_BRANCH << info.startUID << info.endUID);
×
519

520
                m_requestState = StateWait;
×
521
            }
522
            break;
×
523
            case StateDiscoveryEnd:
×
524
            {
525
                if (m_uidMap.isEmpty())
×
526
                    emit requestPopup("Warning", "No RDM devices found");
×
527
                m_requestState = StateNone;
×
528
            }
529
            break;
×
530
            case StatePersonalities:
×
531
            {
532
                waitCount = 0;
533
                QString UID = m_uidMap.firstKey();
534
                m_requestState = StatePersonalityInfo;
×
535
                qDebug() << "Requesting personalities of UID" << UID;
536
                bool result = m_plugin->sendRDMCommand(m_universe, m_line, GET_COMMAND,
×
537
                                                       QVariantList() << UID << PID_DMX_PERSONALITY);
×
538
                if (result == false)
×
539
                {
540
                    requestPopup("Error", "RDM command failed");
×
541
                    m_requestState = StateNone;
×
542
                }
543
            }
×
544
            break;
×
545
            case StateReadSinglePid:
×
546
            {
547
                waitCount = 0;
548
                UIDInfo info = m_uidMap.first();
×
549
                QString UID = m_uidMap.firstKey();
550
                m_requestState = StateWaitPidInfo;
×
551
                qDebug().nospace().noquote() << "Read PID 0x" << QString::number(info.dmxAddress, 16);
552
                QVariantList args;
553
                args << UID;
×
554
                args << info.dmxAddress; // actually the PID to read
×
555
                for (QVariantMap::const_iterator it = info.params.begin(); it != info.params.end(); ++it)
×
556
                    args << it.value(); // add parameters
557

558
                uchar command = info.dmxAddress < 0x04 ? DISCOVERY_COMMAND : GET_COMMAND;
×
559
                bool result = m_plugin->sendRDMCommand(m_universe, m_line, command, args);
×
560
                if (result == false)
×
561
                {
562
                    requestPopup("Error", "RDM command failed");
×
563
                    m_requestState = StateNone;
×
564
                }
565
            }
×
566
            break;
×
567
            case StateWriteSinglePid:
×
568
            {
569
                waitCount = 0;
570
                UIDInfo info = m_uidMap.first();
×
571
                QString UID = m_uidMap.firstKey();
572
                m_requestState = StateWaitPidInfo;
×
573
                qDebug().nospace().noquote() << "Write PID 0x" << QString::number(info.dmxAddress, 16);
574
                QVariantList args;
575
                args << UID;
×
576
                args << info.dmxAddress; // actually the PID to write
×
577
                for (QVariantMap::const_iterator it = info.params.begin(); it != info.params.end(); ++it)
×
578
                    args << it.value(); // forward parameters
579

580
                bool result = m_plugin->sendRDMCommand(m_universe, m_line, SET_COMMAND, args);
×
581
                if (result == false)
×
582
                {
583
                    requestPopup("Error", "RDM command failed");
×
584
                    m_requestState = StateNone;
×
585
                }
586
            }
×
587
            break;
×
588
            default:
×
589
            {
590
                //qDebug() << "[RDM] ....WAIT....";
591
                msleep(50);
×
592
                waitCount++;
×
593
                if (m_requestState == StateWait && waitCount == MAX_WAIT_COUNT)
×
594
                {
595
                    qDebug() << "Exit for timeout...";
596
                    emit requestPopup("Warning", "Process timed out");
×
597
                    m_running = false;
×
598
                }
599
            }
600
            break;
601
        }
602
    }
603

604
    disconnect(m_plugin, SIGNAL(rdmValueChanged(quint32, quint32, QVariantMap)),
×
605
              this, SLOT(slotRDMDataReady(quint32, quint32, QVariantMap)));
606

607
    qDebug() << "Terminating RDM worker thread";
×
608
}
609

610
void RDMWorker::stop()
×
611
{
612
    if (m_running == true)
×
613
    {
614
        m_running = false;
×
615
        wait();
×
616
    }
617
}
×
618

619
void RDMWorker::slotRDMDataReady(quint32 universe, quint32 line, QVariantMap data)
×
620
{
621
    //qDebug() << "Got signal from universe" << universe << ", line" << line;
622
    //qDebug() << "RDM map" << data;
623

624
    if (m_requestState == StateWaitPidInfo)
×
625
    {
626
        QString pidInfo;
627
        for (QVariantMap::const_iterator it = data.begin(); it != data.end(); ++it)
×
628
            pidInfo += QString("<b>%1</b>: %2<br>").arg(it.key()).arg(it.value().toString());
×
629

630
        emit pidInfoReady(pidInfo);
×
631
        m_requestState = StateNone;
×
632
        return;
633
    }
×
634

635
    // check the signal reason
636
    if (data.contains("DISCOVERY_COUNT"))
×
637
    {
638
        int count = data.value("DISCOVERY_COUNT").toInt();
×
639
        for (int i = 0; i < count; i++)
×
640
        {
641
            QString UID = data.value(QString("UID-%1").arg(i)).toString();
×
642
            if (m_uidMap.contains(UID) == false)
×
643
            {
644
                UIDInfo info;
645
                info.universe = universe;
×
646
                info.pluginLine = line;
×
647
                m_uidMap[UID] = info;
×
648

649
                m_plugin->sendRDMCommand(m_universe, m_line, GET_COMMAND,
×
650
                                         QVariantList() << UID << PID_DEVICE_MODEL_DESCRIPTION);
×
651

652
                m_plugin->sendRDMCommand(m_universe, m_line, GET_COMMAND,
×
653
                                         QVariantList() << UID << PID_MANUFACTURER_LABEL);
×
654

655
                m_plugin->sendRDMCommand(m_universe, m_line, GET_COMMAND,
×
656
                                         QVariantList() << UID << PID_DEVICE_INFO);
×
657
            }
×
658
        }
×
659
    }
660
    else if (data.contains("DISCOVERY_ERRORS"))
×
661
    {
662
        if (m_discoveryList.isEmpty())
×
663
            return;
×
664

665
        // Discovery errors mean collisions and/or bad checksum.
666
        // Split the current range into two branches
667
        DiscoveryInfo currentRange = m_discoveryList.first();
×
668
        DiscoveryInfo lowerRange, upperRange;
669

670
        qulonglong midPosition = ((currentRange.startUID & (0x0000800000000000-1)) +
×
671
                                  (currentRange.endUID & (0x0000800000000000-1))) / 2
×
672
                                + ((currentRange.endUID & 0x0000800000000000) ? 0x0000400000000000 : 0)
×
673
                                + ((currentRange.startUID & 0x0000800000000000) ? 0x0000400000000000 :0);
×
674
        lowerRange.startUID = currentRange.startUID;
×
675
        lowerRange.endUID = midPosition;
×
676
        upperRange.startUID = midPosition + 1;
×
677
        upperRange.endUID = currentRange.endUID;
×
678

679
        qDebug() << "Discovery errors detected" << data.value("DISCOVERY_ERRORS").toInt();
680
        //qDebug() << "Add lower range" << QString::number(lowerRange.startUID, 16) << "-" << QString::number(lowerRange.endUID, 16);
681
        //qDebug() << "Add upper range" << QString::number(upperRange.startUID, 16) << "-" << QString::number(upperRange.endUID, 16);
682
        m_discoveryList.removeFirst();
×
683
        m_discoveryList.prepend(lowerRange);
×
684
        m_discoveryList.prepend(upperRange);
×
685
        m_requestState = StateDiscoveryContinue;
×
686
    }
687
    else if (data.contains("DISCOVERY_NO_REPLY"))
×
688
    {
689
        if (m_discoveryList.isEmpty())
×
690
            return;
691

692
        // No reply means a dead branch. Remove it and continue on other branches.
693
        qDebug() << "Discovery: no reply";
694
        m_discoveryList.removeFirst();
×
695
        if (m_discoveryList.isEmpty())
×
696
            m_requestState = StateDiscoveryEnd;
×
697
        else
698
            m_requestState = StateDiscoveryContinue;
×
699
    }
700
    else if (data.contains("UID_INFO"))
×
701
    {
702
        QString UID = data.value("UID_INFO").toString();
×
703
        UIDInfo info = m_uidMap.value(UID);
×
704
        for (QVariantMap::const_iterator it = data.begin(); it != data.end(); ++it)
×
705
        {
706
            QString key = it.key();
707

708
            if (key == "MODEL_NAME")
×
709
            {
710
                info.name = it.value().toString();
×
711
            }
712
            else if (key == "MANUFACTURER")
×
713
            {
714
                info.manufacturer = it.value().toString();
×
715
            }
716
            else if (key == "DMX_CHANNELS")
×
717
            {
718
                info.channels = it.value().toUInt();
×
719
            }
720
            else if (key == "DMX_START_ADDRESS")
×
721
            {
722
                info.dmxAddress = it.value().toUInt();
×
723
                m_uidMap[UID] = info;
×
724
                emit uidFound(UID, info);
×
725
                if (m_discoveryList.isEmpty())
×
726
                {
727
                    m_requestState = StateDiscoveryEnd;
×
728
                }
729
                else
730
                {
731
                    //m_discoveryList.removeFirst();
732
                    m_requestState = StateDiscoveryContinue;
×
733
                }
734
            }
735
            else if (key == "PERS_COUNT")
×
736
            {
737
                for (quint16 p = 0; p < it.value().toUInt(); p++)
×
738
                    m_requestList.append(p + 1);
×
739
            }
740
            else if (key == "PERS_DESC")
×
741
            {
742
                quint16 cIndex = info.params.value("PERS_CURRENT").toUInt();
×
743
                quint16 pIndex = data.value("PERS_INDEX").toUInt();
×
744
                quint16 channels = data.value("PERS_CHANNELS").toUInt();
×
745
                QString label = it.value().toString();
×
746

747
                m_fixtureInfo += QString("<TR><TD CLASS='emphasis'>%1 %2 %3</TD><TD>%4</TD>")
×
748
                                .arg(tr("Personality")).arg(pIndex)
×
749
                                .arg(cIndex == pIndex ? tr("(Selected)") : "").arg(label);
×
750
                m_fixtureInfo += QString("<TD CLASS='emphasis'>%1</TD><TD>%2</TD></TR>")
×
751
                                        .arg(tr("Channels")).arg(channels);
×
752
            }
×
753
            else if (key == "SLOT_LIST")
×
754
            {
755
                QVariant var = it.value();
×
756
                if (m_requestList.isEmpty())
×
757
                {
758
                    QString header("<TR CLASS='hilite'><TD COLSPAN='4'>%1</TD></TR>");
×
759
                    m_fixtureInfo += header.arg(tr("Channel list"));
×
760
                }
×
761

762
                m_requestList.append(var.value<QVector<quint16>>());
×
763

764
                // check if channels don't fit in a single reply
765
                if (info.params.value("Response") == RDMProtocol::responseToString(RESPONSE_TYPE_ACK_OVERFLOW))
×
766
                {
767
                    m_plugin->sendRDMCommand(m_universe, m_line, GET_COMMAND,
×
768
                                             QVariantList() << UID << PID_SLOT_INFO);
×
769
                }
770
                else
771
                {
772
                    m_requestState = StateSlots;
×
773
                }
774
            }
×
775
            else if (key == "SLOT_DESC")
×
776
            {
777
                quint16 slotId = data.value("SLOT_ID").toUInt();
×
778
                QString label = it.value().toString();
×
779

780
                qDebug() << "SLOT label" << label;
781

782
                m_fixtureInfo += QString("<TR><TD CLASS='emphasis'>%1 %2</TD><TD COLSPAN='3'>%3</TD></TR>")
×
783
                                         .arg(tr("Channel")).arg(slotId + 1).arg(label);
×
784
            }
×
785
            else if (key == "PID_LIST")
×
786
            {
787
                QVariant var = it.value();
×
788
                m_requestList = var.value<QVector<quint16>>();
×
789

790
                // remove PIDs handled elsewhere
791
                m_requestList.removeAll(PID_DMX_PERSONALITY);
×
792
                m_requestList.removeAll(PID_DMX_PERSONALITY_DESCRIPTION);
×
793
                m_requestList.removeAll(PID_SLOT_INFO);
×
794
                m_requestList.removeAll(PID_SLOT_DESCRIPTION);
×
795
                std::sort(m_requestList.begin(), m_requestList.end());
×
796

797
                QString header("<TR CLASS='hilite'><TD COLSPAN='4'>%1</TD></TR>");
×
798
                m_fixtureInfo += header.arg(tr("Supported PIDs"));
×
799
                m_requestState = StateSupportedPids;
×
800
            }
×
801
            else if (key == "PID")
×
802
            {
803
                if (m_requestState == StateSupportedPids)
×
804
                {
805
                    quint16 pid = it.value().toUInt();
×
806
                    if (pid < 0x8000 && pid != PID_PARAMETER_DESCRIPTION)
×
807
                    {
808
                        QString sPid = QString("%1").arg(pid, 4, 16, QChar('0'));
×
809
                        m_fixtureInfo += QString("<TR><TD CLASS='emphasis' COLSPAN='4'>PID: 0x%1 (%2)</TD></TR>")
×
810
                                .arg(sPid.toUpper()).arg(RDMProtocol::pidToString(pid));
×
811
                    }                }
×
812
                else if (m_requestState == StateReadSinglePid)
813
                {
814
                    // TODO
815
                }
816
            }
817
            else if (key == "PID_DESC")
×
818
            {
819
                if (m_requestState == StateSupportedPids)
×
820
                {
821
                    quint16 pid = data.value("PID_INFO").toUInt();
×
822
                    QString sPid = QString("%1").arg(pid, 4, 16, QChar('0'));
×
823
                    m_fixtureInfo += QString("<TR><TD CLASS='emphasis' COLSPAN='4'>PID: 0x%1 (%2)</TD></TR>")
×
824
                            .arg(sPid.toUpper()).arg(it.value().toString());
×
825
                }
×
826
                else if (m_requestState == StateReadSinglePid)
827
                {
828
                    // TODO
829
                }
830
            }
831
            else
832
            {
833
                info.params.insert(it.key(), it.value());
×
834
            }
835

836
            //qDebug() << it.key() << it.value();
837

838
            m_uidMap[UID] = info;
×
839
        }
×
840

841
        if (m_requestState == StatePersonalityInfo)
×
842
        {
843
            if (m_requestList.isEmpty() == false)
×
844
            {
845
                quint16 idx = m_requestList.takeFirst();
×
846
                m_plugin->sendRDMCommand(m_universe, m_line, GET_COMMAND,
×
847
                                         QVariantList() << UID << PID_DMX_PERSONALITY_DESCRIPTION << 1 << idx);
×
848
            }
849
            else
850
            {
851
                m_plugin->sendRDMCommand(m_universe, m_line, GET_COMMAND,
×
852
                                       QVariantList() << UID << PID_SLOT_INFO);
×
853
            }
854
        }
855
        else if (m_requestState == StateSlots)
×
856
        {
857
            if (m_requestList.isEmpty() == false)
×
858
            {
859
                quint16 slotId = m_requestList.takeFirst();
×
860
                m_plugin->sendRDMCommand(m_universe, m_line, GET_COMMAND,
×
861
                                         QVariantList() << UID << PID_SLOT_DESCRIPTION << 2 << slotId);
×
862
            }
863
            else
864
            {
865
                m_plugin->sendRDMCommand(m_universe, m_line, GET_COMMAND,
×
866
                                         QVariantList() << UID << PID_SUPPORTED_PARAMETERS);
×
867
            }
868
        }
869
        else if (m_requestState == StateSupportedPids)
×
870
        {
871
            if (m_requestList.isEmpty() == false)
×
872
            {
873
                quint16 pid = m_requestList.takeFirst();
×
874

875
                if (pid >= 0x8000)
×
876
                    m_plugin->sendRDMCommand(m_universe, m_line, GET_COMMAND,
×
877
                                             QVariantList() << UID << PID_PARAMETER_DESCRIPTION << 2 << pid);
×
878
                else
879
                    m_plugin->sendRDMCommand(m_universe, m_line, GET_COMMAND,
×
880
                                             QVariantList() << UID << pid);
×
881
            }
882
            else
883
            {
884
                emit fixtureInfoReady(m_fixtureInfo);
×
885
                m_requestState = StateNone;
×
886
            }
887
        }
888
    }
×
889
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc