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

mcallegari / qlcplus / 7307414152

23 Dec 2023 09:18AM CUT coverage: 32.067%. Remained the same
7307414152

push

github

web-flow
Merge pull request #1493 from yestalgia/readme

Update Readme

15169 of 47304 relevant lines covered (32.07%)

23733.74 hits per line

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

0.0
/plugins/enttecwing/src/enttecwing.cpp
1
/*
2
  Q Light Controller
3
  enttecwing.cpp
4

5
  Copyright (c) Heikki Junnila
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 <QStringList>
21
#include <QUdpSocket>
22
#include <QDebug>
23

24
#include "playbackwing.h"
25
#include "shortcutwing.h"
26
#include "programwing.h"
27
#include "enttecwing.h"
28
#include "wing.h"
29

30
/*****************************************************************************
31
 * Initialization
32
 *****************************************************************************/
33

34
void EnttecWing::init()
×
35
{
36
    /* Create a new UDP socket and start listening to packets coming to
37
       any local address. */
38
    m_socket = new QUdpSocket(this);
×
39
    reBindSocket();
×
40
    connect(m_socket, SIGNAL(readyRead()), this, SLOT(slotReadSocket()));
×
41
}
×
42

43
EnttecWing::~EnttecWing()
×
44
{
45
    while (m_devices.isEmpty() == false)
×
46
        delete m_devices.takeFirst();
×
47
}
×
48

49
QString EnttecWing::name()
×
50
{
51
    return QString("ENTTEC Wing");
×
52
}
53

54
int EnttecWing::capabilities() const
×
55
{
56
    return QLCIOPlugin::Output | QLCIOPlugin::Input | QLCIOPlugin::Feedback;
×
57
}
58

59
bool EnttecWing::reBindSocket()
×
60
{
61
    if (m_socket->state() == QAbstractSocket::BoundState)
×
62
        m_socket->close();
×
63

64
    if (m_socket->bind(QHostAddress::Any, Wing::UDPPort) == false)
×
65
    {
66
        m_errorString = m_socket->errorString();
×
67
        qWarning() << Q_FUNC_INFO << m_errorString;
×
68
        return false;
×
69
    }
70
    else
71
    {
72
        m_errorString.clear();
×
73
    }
74
    return true;
×
75
}
76

77
/*****************************************************************************
78
 * Outputs
79
 *****************************************************************************/
80

81
QStringList EnttecWing::outputs()
×
82
{
83
    QStringList list;
×
84
    QListIterator <Wing*> it(m_devices);
×
85
    while (it.hasNext() == true)
×
86
        list << it.next()->name();
×
87
    return list;
×
88
}
89

90
/*****************************************************************************
91
 * Inputs
92
 *****************************************************************************/
93

94
bool EnttecWing::openInput(quint32 input, quint32 universe)
×
95
{
96
    Q_UNUSED(input);
97
    Q_UNUSED(universe)
98
    return reBindSocket();
×
99
}
100

101
void EnttecWing::closeInput(quint32 input, quint32 universe)
×
102
{
103
    Q_UNUSED(input)
104
    Q_UNUSED(universe)
105
}
×
106

107
QStringList EnttecWing::inputs()
×
108
{
109
    QStringList list;
×
110
    QListIterator <Wing*> it(m_devices);
×
111
    while (it.hasNext() == true)
×
112
        list << it.next()->name();
×
113
    return list;
×
114
}
115

116
QString EnttecWing::pluginInfo()
×
117
{
118
    QString str;
×
119

120
    str += QString("<HTML>");
×
121
    str += QString("<HEAD>");
×
122
    str += QString("<TITLE>%1</TITLE>").arg(name());
×
123
    str += QString("</HEAD>");
×
124
    str += QString("<BODY>");
×
125

126
    str += QString("<P>");
×
127
    str += QString("<H3>%1</H3>").arg(name());
×
128
    str += tr("This plugin provides input support for Enttec Playback "
×
129
              "and Enttec Shortcut Wings.");
×
130
    str += QString("</P>");
×
131

132
    return str;
×
133
}
134

135
QString EnttecWing::inputInfo(quint32 input)
×
136
{
137
    QString str;
×
138

139
    if (input == QLCIOPlugin::invalidLine())
×
140
    {
141
        /* Plugin or just an invalid input selected. Display the error. */
142
        if (m_socket->state() != QAbstractSocket::BoundState)
×
143
        {
144
            str += QString("<P>");
×
145
            str += tr("Unable to bind to UDP port %1:").arg(Wing::UDPPort);
×
146
            str += QString(" %1.").arg(m_errorString);
×
147
            str += QString("</P>");
×
148
        }
149
        else
150
        {
151
            str += QString("<P>");
×
152
            str += tr("Listening to UDP port %1.").arg(Wing::UDPPort);
×
153
            str += QString("</P>");
×
154
        }
155
    }
156
    else
157
    {
158
        /* A specific input line selected. Display its information if
159
           available. */
160
        Wing* dev = device(input);
×
161
        if (dev != NULL)
×
162
            str += dev->infoText();
×
163
    }
164

165
    str += QString("</BODY>");
×
166
    str += QString("</HTML>");
×
167

168
    return str;
×
169
}
170

171
void EnttecWing::sendFeedBack(quint32 universe, quint32 input,
×
172
                              quint32 channel, uchar value, const QString &)
173
{
174
    Q_UNUSED(universe)
175

176
    Wing* wing = device(input);
×
177
    if (wing != NULL)
×
178
        wing->feedBack(channel, value);
×
179
}
×
180

181
/*****************************************************************************
182
 * Configuration
183
 *****************************************************************************/
184

185
void EnttecWing::configure()
×
186
{
187
    reBindSocket();
×
188
    emit configurationChanged();
×
189
}
×
190

191
bool EnttecWing::canConfigure()
×
192
{
193
    return true;
×
194
}
195

196
/*****************************************************************************
197
 * Devices
198
 *****************************************************************************/
199

200
Wing* EnttecWing::createWing(QObject* parent, const QHostAddress& address,
×
201
                              const QByteArray& data)
202
{
203
    Wing* wing = NULL;
×
204

205
    /* Check, that the message is from an ENTTEC Wing */
206
    if (Wing::isOutputData(data) == false)
×
207
        return NULL;
×
208

209
    switch (Wing::resolveType(data))
×
210
    {
211
    case Wing::Playback:
×
212
        wing = new PlaybackWing(parent, address, data);
×
213
        break;
×
214
    case Wing::Shortcut:
×
215
        wing = new ShortcutWing(parent, address, data);
×
216
        break;
×
217
    case Wing::Program:
×
218
        wing = new ProgramWing(parent, address, data);
×
219
        break;
×
220
    default:
×
221
        wing = NULL;
×
222
        break;
×
223
    }
224

225
    return wing;
×
226
}
227

228
Wing* EnttecWing::device(const QHostAddress& address, Wing::Type type)
×
229
{
230
    QListIterator <Wing*> it(m_devices);
×
231
    while (it.hasNext() == true)
×
232
    {
233
        Wing* dev = it.next();
×
234
        if (dev->address() == address && dev->type() == type)
×
235
            return dev;
×
236
    }
237

238
    return NULL;
×
239
}
240

241
Wing* EnttecWing::device(quint32 index)
×
242
{
243
    if (index < quint32(m_devices.count()))
×
244
        return m_devices.at(index);
×
245
    else
246
        return NULL;
×
247
}
248

249
static bool wing_device_sort(const Wing* d1, const Wing* d2)
×
250
{
251
    /* Sort devices based on their addresses. Lexical sorting is enough. */
252
    return (d1->address().toString() < d2->address().toString());
×
253
}
254

255
void EnttecWing::addDevice(Wing* device)
×
256
{
257
    Q_ASSERT(device != NULL);
×
258

259
    connect(device, SIGNAL(valueChanged(quint32,uchar)),
×
260
            this, SLOT(slotValueChanged(quint32,uchar)));
261

262
    m_devices.append(device);
×
263

264
    /* To maintain some persistency with the indices of multiple devices
265
       between sessions they need to be sorted according to some
266
       (semi-)permanent criteria. Their addresses shouldn't change too
267
       often, so let's use that. */
268
    std::sort(m_devices.begin(), m_devices.end(), wing_device_sort);
×
269

270
    emit configurationChanged();
×
271
}
×
272

273
void EnttecWing::removeDevice(Wing* device)
×
274
{
275
    Q_ASSERT(device != NULL);
×
276
    m_devices.removeAll(device);
×
277
    delete device;
×
278

279
    emit configurationChanged();
×
280
}
×
281

282
void EnttecWing::slotReadSocket()
×
283
{
284
    while (m_socket->hasPendingDatagrams() == true)
×
285
    {
286
        QHostAddress sender;
×
287
        QByteArray data;
×
288
        Wing* wing;
289

290
        /* Read data from socket */
291
        data.resize(m_socket->pendingDatagramSize());
×
292
        m_socket->readDatagram(data.data(), data.size(), &sender);
×
293

294
        /* Check, whether we already have a device from this address */
295
        wing = device(sender, Wing::resolveType(data));
×
296
        if (wing == NULL)
×
297
        {
298
            /* New address. Create a new device. */
299
            wing = createWing(this, sender, data);
×
300
            if (wing != NULL)
×
301
                addDevice(wing);
×
302
        }
303
        else
304
        {
305
            // Since creating a wing already does parseData, don't do it again
306
            wing->parseData(data);
×
307
        }
308
    }
309
}
×
310

311
void EnttecWing::slotValueChanged(quint32 channel, uchar value)
×
312
{
313
    Wing* wing = qobject_cast<Wing*> (QObject::sender());
×
314
    emit valueChanged(UINT_MAX, m_devices.indexOf(wing), channel, value);
×
315
}
×
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