• 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/simpledeskengine.cpp
1
/*
2
  Q Light Controller Plus
3
  simpledeskengine.cpp
4

5
  Copyright (c) Heikki Junnila
6
                Massimo Callegari
7

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

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

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

21
#include <QXmlStreamReader>
22
#include <QXmlStreamWriter>
23
#include <QMutexLocker>
24
#include <QVariant>
25
#include <QDebug>
26

27
#include "simpledeskengine.h"
28
#include "genericfader.h"
29
#include "mastertimer.h"
30
#include "fadechannel.h"
31
#include "cuestack.h"
32
#include "universe.h"
33
#include "doc.h"
34

35
#define PROP_ID "id"
36

37
/****************************************************************************
38
 * Initialization
39
 ****************************************************************************/
40

41
SimpleDeskEngine::SimpleDeskEngine(Doc* doc)
×
42
    : QObject(doc)
43
    , m_doc(doc)
×
44
{
45
    qDebug() << Q_FUNC_INFO;
46
    Q_ASSERT(doc != NULL);
47
    doc->masterTimer()->registerDMXSource(this);
×
48
}
×
49

50
SimpleDeskEngine::~SimpleDeskEngine()
×
51
{
52
    qDebug() << Q_FUNC_INFO;
53

54
    clearContents();
×
55
    m_doc->masterTimer()->unregisterDMXSource(this);
×
56
}
×
57

58
void SimpleDeskEngine::clearContents()
×
59
{
60
    qDebug() << Q_FUNC_INFO;
61

62
    // Stop all cuestacks and wait for each of them to stop
63
    foreach (CueStack* cs, m_cueStacks.values())
×
64
    {
65
        cs->stop();
×
66
        while (cs->isStarted() == true) { /* NOP */ }
×
67
    }
68

69
    QMutexLocker locker(&m_mutex);
×
70
    foreach (CueStack* cs, m_cueStacks.values())
×
71
        delete cs;
×
72
    m_cueStacks.clear();
×
73
    m_values.clear();
×
74
}
×
75

76
/****************************************************************************
77
 * Universe Values
78
 ****************************************************************************/
79

80
void SimpleDeskEngine::setValue(uint channel, uchar value)
×
81
{
82
    //qDebug() << Q_FUNC_INFO << "channel:" << channel << ", value:" << value;
83

84
    QMutexLocker locker(&m_mutex);
×
85
    m_values[channel] = value;
×
86
    setChanged(true);
87
}
×
88

89
uchar SimpleDeskEngine::value(uint channel) const
×
90
{
91
    QMutexLocker locker(&m_mutex);
×
92
    if (m_values.contains(channel) == true)
×
93
        return m_values[channel];
×
94
    else
95
        return 0;
96
}
97

98
bool SimpleDeskEngine::hasChannel(uint channel)
×
99
{
100
    QMutexLocker locker(&m_mutex);
×
101
    return m_values.contains(channel);
×
102
}
103

104
void SimpleDeskEngine::setCue(const Cue& cue)
×
105
{
106
    qDebug() << Q_FUNC_INFO;
107

108
    QMutexLocker locker(&m_mutex);
×
109
    m_values = cue.values();
×
110
    setChanged(true);
111
}
×
112

113
Cue SimpleDeskEngine::cue() const
×
114
{
115
    QMutexLocker locker(&m_mutex);
×
116
    return Cue(m_values);
×
117
}
118

119
void SimpleDeskEngine::resetUniverse(int universe)
×
120
{
121
    qDebug() << Q_FUNC_INFO;
122

123
    // remove values previously set on universe
124
    QMutexLocker locker(&m_mutex);
×
125
    QHashIterator <uint,uchar> it(m_values);
×
126
    while (it.hasNext() == true)
×
127
    {
128
        it.next();
×
129
        int uni = it.key() >> 9;
×
130
        if (uni == universe)
×
131
            m_values.remove(it.key());
×
132
    }
133

134
    // add command to queue. Will be taken care of at the next writeDMX call
135
    m_commandQueue.append(QPair<int,quint32>(ResetUniverse, universe));
×
136
    setChanged(true);
137
}
×
138

139
void SimpleDeskEngine::resetChannel(uint channel)
×
140
{
141
    QMutexLocker locker(&m_mutex);
×
142
    if (m_values.contains(channel))
×
143
        m_values.remove(channel);
×
144

145
    // add command to queue. Will be taken care of at the next writeDMX call
146
    m_commandQueue.append(QPair<int,quint32>(ResetChannel, channel));
×
147
    setChanged(true);
148
}
×
149

150
/****************************************************************************
151
 * Cue Stacks
152
 ****************************************************************************/
153

154
CueStack* SimpleDeskEngine::cueStack(uint stack)
×
155
{
156
    QMutexLocker locker(&m_mutex);
×
157

158
    if (m_cueStacks.contains(stack) == false)
×
159
    {
160
        m_cueStacks[stack] = createCueStack();
×
161
        m_cueStacks[stack]->setProperty(PROP_ID, stack);
×
162
    }
163

164
    return m_cueStacks[stack];
×
165
}
166

167
CueStack* SimpleDeskEngine::createCueStack()
×
168
{
169
    qDebug() << Q_FUNC_INFO;
170

171
    CueStack* cs = new CueStack(m_doc);
×
172
    Q_ASSERT(cs != NULL);
173
    connect(cs, SIGNAL(currentCueChanged(int)), this, SLOT(slotCurrentCueChanged(int)));
×
174
    connect(cs, SIGNAL(started()), this, SLOT(slotCueStackStarted()));
×
175
    connect(cs, SIGNAL(stopped()), this, SLOT(slotCueStackStopped()));
×
176
    return cs;
×
177
}
178

179
void SimpleDeskEngine::slotCurrentCueChanged(int index)
×
180
{
181
    qDebug() << Q_FUNC_INFO;
182

183
    if (sender() == NULL)
×
184
        return;
185

186
    uint stack = sender()->property(PROP_ID).toUInt();
×
187
    emit currentCueChanged(stack, index);
×
188
}
189

190
void SimpleDeskEngine::slotCueStackStarted()
×
191
{
192
    qDebug() << Q_FUNC_INFO;
193

194
    if (sender() == NULL)
×
195
        return;
196

197
    uint stack = sender()->property(PROP_ID).toUInt();
×
198
    emit cueStackStarted(stack);
×
199
}
200

201
void SimpleDeskEngine::slotCueStackStopped()
×
202
{
203
    qDebug() << Q_FUNC_INFO;
204

205
    if (sender() == NULL)
×
206
        return;
207

208
    uint stack = sender()->property(PROP_ID).toUInt();
×
209
    emit cueStackStopped(stack);
×
210
}
211

212
/************************************************************************
213
 * Save & Load
214
 ************************************************************************/
215

216
bool SimpleDeskEngine::loadXML(QXmlStreamReader &root)
×
217
{
218
    if (root.name() != KXMLQLCSimpleDeskEngine)
×
219
    {
220
        qWarning() << Q_FUNC_INFO << "Simple Desk Engine node not found";
×
221
        return false;
×
222
    }
223

224
    while (root.readNextStartElement())
×
225
    {
226
        if (root.name() == KXMLQLCCueStack)
×
227
        {
228
            uint id = CueStack::loadXMLID(root);
×
229
            if (id != UINT_MAX)
×
230
            {
231
                CueStack* cs = cueStack(id);
×
232
                cs->loadXML(root);
×
233
            }
234
            else
235
            {
236
                qWarning() << Q_FUNC_INFO << "Missing CueStack ID!";
×
237
            }
238
        }
239
        else
240
        {
241
            qWarning() << Q_FUNC_INFO << "Unrecognized Simple Desk Engine tag:" << root.name();
×
242
            root.skipCurrentElement();
×
243
        }
244
    }
245

246
    return true;
247
}
248

249
bool SimpleDeskEngine::saveXML(QXmlStreamWriter *doc) const
×
250
{
251
    qDebug() << Q_FUNC_INFO;
252
    Q_ASSERT(doc != NULL);
253

254
    doc->writeStartElement(KXMLQLCSimpleDeskEngine);
×
255

256
    QMutexLocker locker(&m_mutex);
×
257

258
    QHashIterator <uint,CueStack*> it(m_cueStacks);
×
259
    while (it.hasNext() == true)
×
260
    {
261
        it.next();
×
262

263
        // Save CueStack only if it contains something
264
        const CueStack* cs = it.value();
×
265
        if (cs->cues().size() > 0)
×
266
            cs->saveXML(doc, it.key());
×
267
    }
268

269
    /* End the <Engine> tag */
270
    doc->writeEndElement();
×
271

272
    return true;
×
273
}
274

275
/****************************************************************************
276
 * DMXSource
277
 ****************************************************************************/
278

279
FadeChannel *SimpleDeskEngine::getFader(QList<Universe *> universes, quint32 universeID,
×
280
                                        quint32 fixtureID, quint32 channel)
281
{
282
    // get the universe Fader first. If doesn't exist, create it
283
    QSharedPointer<GenericFader> fader = m_fadersMap.value(universeID, QSharedPointer<GenericFader>());
×
284
    if (fader.isNull())
×
285
    {
286
        fader = universes[universeID]->requestFader(Universe::SimpleDesk);
×
287
        m_fadersMap[universeID] = fader;
×
288
    }
289

290
    return fader->getChannelFader(m_doc, universes[universeID], fixtureID, channel);
×
291
}
292

293
void SimpleDeskEngine::writeDMX(MasterTimer *timer, QList<Universe *> ua)
×
294
{
295
    QMutexLocker locker(&m_mutex);
×
296

297
    if (m_commandQueue.isEmpty() == false)
×
298
    {
299
        for (int i = 0; i < m_commandQueue.count(); i++)
×
300
        {
301
            QPair<int,quint32> command = m_commandQueue.at(i);
×
302
            if (command.first == ResetUniverse)
×
303
            {
304
                quint32 universe = command.second;
×
305
                if (universe >= (quint32)ua.count())
×
306
                    continue;
×
307

308
                ua[universe]->reset(0, 512);
×
309

310
                QSharedPointer<GenericFader> fader = m_fadersMap.value(universe, QSharedPointer<GenericFader>());
×
311
                if (!fader.isNull())
×
312
                {
313
                    // loop through all active fadechannels and restore defualt values
314
                    QHashIterator<quint32, FadeChannel> it(fader->channels());
×
315
                    while (it.hasNext() == true)
×
316
                    {
317
                        it.next();
×
318
                        FadeChannel fc = it.value();
×
319
                        Fixture *fixture = m_doc->fixture(fc.fixture());
×
320
                        quint32 chIndex = fc.channel();
×
321

322
                        if (fixture != NULL)
×
323
                        {
324
                            const QLCChannel *ch = fixture->channel(chIndex);
×
325
                            if (ch != NULL)
×
326
                            {
327
                                qDebug() << "Restoring default value of fixture" << fixture->id()
328
                                         << "channel" << chIndex << "value" << ch->defaultValue();
329
                                chIndex += fixture->address();
×
330

331
                                if (fixture->crossUniverse() && chIndex > 511)
×
332
                                    chIndex -= 512;
×
333

334
                                ua[universe]->setChannelDefaultValue(chIndex, ch->defaultValue());
×
335
                            }
336
                        }
337
                    }
×
338
                    ua[universe]->dismissFader(fader);
×
339
                    m_fadersMap.remove(universe);
×
340
                }
341
            }
342
            else if (command.first == ResetChannel)
×
343
            {
344
                quint32 channel = command.second;
345
                quint32 universe = channel >> 9;
×
346
                QSharedPointer<GenericFader> fader = m_fadersMap.value(universe, QSharedPointer<GenericFader>());
×
347
                if (!fader.isNull())
×
348
                {
349
                    FadeChannel fc(m_doc, Fixture::invalidId(), channel);
×
350
                    Fixture *fixture = m_doc->fixture(fc.fixture());
×
351
                    quint32 chIndex = fc.channel();
×
352
                    fader->remove(&fc);
×
353

354
                    if (fixture != NULL && fixture->crossUniverse() && channel > 511)
×
355
                        channel -= 512;
×
356

357
                    ua[universe]->reset(channel & 0x01FF, 1);
×
358

359
                    if (fixture != NULL)
×
360
                    {
361
                        const QLCChannel *ch = fixture->channel(chIndex);
×
362
                        if (ch != NULL)
×
363
                        {
364
                            qDebug() << "Restoring default value of fixture" << fixture->id()
365
                                     << "channel" << chIndex << "value" << ch->defaultValue();
366
                            ua[universe]->setChannelDefaultValue(channel, ch->defaultValue());
×
367
                        }
368
                    }
369
                }
×
370
            }
371
        }
372
        m_commandQueue.clear();
×
373
    }
374

375
    if (hasChanged())
×
376
    {
377
        QHashIterator <uint,uchar> it(m_values);
×
378
        while (it.hasNext() == true)
×
379
        {
380
            it.next();
×
381
            int uni = it.key() >> 9;
×
382
            int address = it.key();
383
            uchar value = it.value();
×
384
            FadeChannel *fc = getFader(ua, uni, Fixture::invalidId(), address);
×
385
            fc->setCurrent(value);
×
386
            fc->setTarget(value);
×
387
            fc->addFlag(FadeChannel::Override);
×
388
        }
389
        setChanged(false);
390
    }
391

392
    foreach (CueStack *cueStack, m_cueStacks)
×
393
    {
394
        if (cueStack == NULL)
×
395
            continue;
×
396

397
        if (cueStack->isRunning())
×
398
        {
399
            if (!cueStack->isStarted())
×
400
                cueStack->preRun();
×
401

402
            cueStack->write(ua);
×
403
        }
404
        else
405
        {
406
            if (cueStack->isStarted())
×
407
                cueStack->postRun(timer, ua);
×
408
        }
409
    }
410
}
×
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