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

mcallegari / qlcplus / 8961243534

05 May 2024 09:23PM UTC coverage: 32.068% (+4.0%) from 28.094%
8961243534

push

github

mcallegari
Merge branch 'master' into qmltoqt6

902 of 2557 new or added lines in 140 files covered. (35.28%)

166 existing lines in 76 files now uncovered.

15395 of 48008 relevant lines covered (32.07%)

22949.67 hits per line

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

17.46
/plugins/artnet/src/artnetpacketizer.cpp
1
/*
2
  Q Light Controller Plus
3
  artnetpacketizer.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 "artnetpacketizer.h"
21
#include "rdmprotocol.h"
22

23
#include <QStringList>
24
#include <QDebug>
25

26
ArtNetPacketizer::ArtNetPacketizer()
1✔
27
{
28
    // Initialize a commond header.
29
    // Changing only the tenth byte will create a valid ArtNet header
30
    m_commonHeader.clear();
1✔
31
    m_commonHeader.append(ARTNET_CODE_STR);
1✔
32
    m_commonHeader.append('\0');
1✔
33

34
    // empty opcode
35
    m_commonHeader.append('\0');
1✔
36
    m_commonHeader.append('\0');
1✔
37

38
    // version 14 by default
39
    m_commonHeader.append('\0');
1✔
40
    m_commonHeader.append((char)0x0e);
1✔
41

42
    m_sequence[0] = 1;
1✔
43
    m_sequence[1] = 1;
1✔
44
    m_sequence[2] = 1;
1✔
45
    m_sequence[3] = 1;
1✔
46
}
1✔
47

48
ArtNetPacketizer::~ArtNetPacketizer()
1✔
49
{
50
}
1✔
51

52
/*********************************************************************
53
 * Sender functions
54
 *********************************************************************/
55

56
void ArtNetPacketizer::setupArtNetPoll(QByteArray& data)
×
57
{
58
    data.clear();
×
59
    data.append(m_commonHeader);
×
60
    const char opCodeMSB = (ARTNET_POLL >> 8);
×
61
    data[9] = opCodeMSB;
×
62
    data.append((char)0x02); // TalkToMe
×
63
    data.append('\0'); // Priority
×
64
}
×
65

NEW
66
void ArtNetPacketizer::setupArtNetPollReply(QByteArray &data, QHostAddress ipAddr, QString MACaddr, quint32 universe, bool isInput)
×
67
{
68
    int i = 0;
×
69
    data.clear();
×
70
    data.append(m_commonHeader);
×
71
    data.remove(9, 2);
×
72
    const char opCodeMSB = (ARTNET_POLLREPLY >> 8);
×
73
    data[9] = opCodeMSB;
×
74
    QString ipStr = ipAddr.toString();
×
75
    QStringList ipAddrList = ipStr.split(".");
×
76
    foreach (QString val, ipAddrList)
×
77
        data.append((char)val.toInt()); // IP address[4]
×
78
    data.append((char)0x36);     // Port LSB
×
79
    data.append((char)0x19);     // Port MSB
×
80
    data.append((char)0x04);     // Version MSB
×
81
    data.append((char)0x20);     // Version LSB
×
82
    data.append((char)0x00);     // Sub Switch MSB
×
83
    data.append((char)0x00);     // Sub Switch LSB
×
84
    data.append((char)0xFF);     // OEM Value MSB
×
85
    data.append((char)0xFF);     // OEM Value LSB
×
86
    data.append((char)0x00);     // UBEA version
×
87
    data.append((char)0xF0);     // Status1 - Ready and booted
×
88
    data.append((char)0xFF);     // ESTA Manufacturer MSB
×
89
    data.append((char)0xFF);     // ESTA Manufacturer LSB
×
90

91
    data.append("QLC+");   // Short Name
×
92
    for (i = 0; i < 14; i++)
×
93
        data.append((char)0x00); // 14 bytes of stuffing
×
94
    data.append("Q Light Controller Plus - ArtNet interface"); // Long Name
×
NEW
95
    for (i = 0; i < 22; i++) // 64-42 bytes of stuffing. 42 is the length of the long name
×
96
        data.append((char)0x00);
×
97

98
    for (i = 0; i < 64; i++)
×
99
        data.append((char)0x00); // Node report
×
NEW
100
    data.append((char)0x00);     // NumPortsHi
×
NEW
101
    data.append((char)0x01);     // NumPortsLo
×
NEW
102
    data.append(isInput ? (char)0x40 : (char)0x80); // PortTypes[0]: can input or output DMX512 data
×
NEW
103
    data.append((char)0x00);     // PortTypes[1]: nothing
×
NEW
104
    data.append((char)0x00);     // PortTypes[2]: nothing
×
NEW
105
    data.append((char)0x00);     // PortTypes[3]: nothing
×
106

NEW
107
    data.append(isInput ? (char)0x80 : (char)0x00); // GoodInput[0] - input status port 1
×
NEW
108
    data.append((char)0x00);     // GoodInput[1] - input status port 2
×
NEW
109
    data.append((char)0x00);     // GoodInput[2] - input status port 3
×
NEW
110
    data.append((char)0x00);     // GoodInput[3] - input status port 4
×
111

NEW
112
    data.append(isInput ? (char)0x00 : (char)0x80); // GoodOutputA[0] - output status port 1
×
NEW
113
    data.append((char)0x00);     // GoodOutputA[0] - output status port 2
×
NEW
114
    data.append((char)0x00);     // GoodOutputA[0] - output status port 3
×
NEW
115
    data.append((char)0x00);     // GoodOutputA[0] - output status port 4
×
116

NEW
117
    data.append(isInput ? (char)universe : (char)0x00); // SwIn[0] - port 1
×
NEW
118
    data.append((char)0x00);     // SwIn[1] - port 2
×
NEW
119
    data.append((char)0x00);     // SwIn[2] - port 3
×
NEW
120
    data.append((char)0x00);     // SwIn[3] - port 4
×
121

NEW
122
    data.append(isInput ? (char)0x00 : (char)universe); // SwOut[0] - port 1
×
NEW
123
    data.append((char)0x00);     // SwOut[1] - port 2
×
NEW
124
    data.append((char)0x00);     // SwOut[2] - port 3
×
NEW
125
    data.append((char)0x00);     // SwOut[3] - port 4
×
126
    for (i = 0; i < 7; i++)
×
127
        data.append((char)0x00);  // SwVideo, SwMacro, SwRemote and 4 spare bytes
×
128
    QStringList MAC = MACaddr.split(":");
×
129
    foreach (QString couple, MAC)
×
130
    {
131
        bool ok;
132
        data.append((char)couple.toInt(&ok, 16));
×
133
    }
134
    for (i = 0; i < 32; i++)
×
135
        data.append((char)0x00); // bindIp[4], BindIndex, Status2 and filler
×
136
}
×
137

138
void ArtNetPacketizer::setupArtNetDmx(QByteArray& data, const int &universe, const QByteArray &values)
4✔
139
{
140
    data.clear();
4✔
141
    data.append(m_commonHeader);
4✔
142
    const char opCodeMSB = (ARTNET_DMX >> 8);
4✔
143
    data[9] = opCodeMSB;
4✔
144
    data.append(m_sequence[universe]); // Sequence
4✔
145
    data.append('\0'); // Physical
4✔
146
    data.append((char)(universe & 0x00FF));
4✔
147
    data.append((char)(universe >> 8));
4✔
148
    int padLength = values.isEmpty() ? 2 : (values.length() % 2); // length must be even in the range 2-512
4✔
149
    int len = values.length() + padLength;
4✔
150
    data.append((char)(len >> 8));
4✔
151
    data.append((char)(len & 0x00FF));
4✔
152
    data.append(values);
4✔
153
    data.append(QByteArray(padLength, 0));
4✔
154

155
    if (m_sequence[universe] == 0xff)
4✔
156
        m_sequence[universe] = 1;
×
157
    else
158
        m_sequence[universe]++;
4✔
159
}
4✔
160

161
void ArtNetPacketizer::setupArtNetTodRequest(QByteArray &data, const int &universe)
×
162
{
163
    data.clear();
×
164
    data.append(m_commonHeader);
×
165
    data[9] = char(ARTNET_TODREQUEST >> 8);
×
166
    data.append(char(0x00)); // Filler1
×
167
    data.append(char(0x00)); // Filler2
×
168
    data.append(char(0x00)); // Spare1
×
169
    data.append(char(0x00)); // Spare2
×
170
    data.append(char(0x00)); // Spare3
×
171
    data.append(char(0x00)); // Spare4
×
172
    data.append(char(0x00)); // Spare5
×
173
    data.append(char(0x00)); // Spare6
×
174
    data.append(char(0x00)); // Spare7
×
175

176
    data.append((char)(universe >> 8));     // Net
×
177
    data.append(char(0x00));                // Command: TodFull
×
178
    data.append(char(0x01));                // AddCount
×
179
    data.append((char)(universe & 0x00FF)); // Address
×
180
}
×
181

182
void ArtNetPacketizer::setupArtNetRdm(QByteArray &data, const int &universe, uchar command, QVariantList params)
×
183
{
184
    RDMProtocol rdm;
×
185
    QByteArray ba;
×
186

187
    data.clear();
×
188
    data.append(m_commonHeader);
×
189
    data[9] = char(ARTNET_RDM >> 8);
×
190
    data.append(char(0x01)); // RDM version 1.0
×
191
    data.append(char(0x00)); // Filler1
×
192
    data.append(char(0x00)); // Spare1
×
193
    data.append(char(0x00)); // Spare2
×
194
    data.append(char(0x00)); // Spare3
×
195
    data.append(char(0x00)); // Spare4
×
196
    data.append(char(0x00)); // Spare5
×
197
    data.append(char(0x00)); // Spare6
×
198
    data.append(char(0x00)); // Spare7
×
199

200
    data.append((char)(universe >> 8));     // Net
×
201
    data.append(char(0x00));                // ArProcess
×
202
    data.append((char)(universe & 0x00FF)); // Address
×
203

204
    rdm.packetizeCommand(command, params, false, ba);
×
205
    data.append(ba);
×
206
}
×
207

208
/*********************************************************************
209
 * Receiver functions
210
 *********************************************************************/
211

212
bool ArtNetPacketizer::checkPacketAndCode(QByteArray const& data, quint16 &code)
×
213
{
214
    /* An ArtNet header must be at least 12 bytes long */
215
    if (data.length() < 12)
×
216
        return false;
×
217

218
    /* Check "Art-Net" keyword presence */
219
    if (data.indexOf(ARTNET_CODE_STR) != 0)
×
220
        return false;
×
221

222
    if (data.at(7) != 0x00)
×
223
        return false;
×
224

NEW
225
    code = (quint16(data.at(9)) << 8) + quint16(data.at(8));
×
226

227
    return true;
×
228
}
229

230
bool ArtNetPacketizer::fillArtPollReplyInfo(QByteArray const& data, ArtNetNodeInfo& info)
×
231
{
232
    if (data.isNull())
×
233
        return false;
×
234

235
    QByteArray shortName = data.mid(26, 18);
×
236
    QByteArray longName = data.mid(44, 64);
×
237
    info.shortName = QString(shortName.data()).simplified();
×
238
    info.longName = QString(longName.data()).simplified();
×
239

240
    qDebug() << "getArtPollReplyInfo shortName: " << info.shortName;
×
241
    qDebug() << "getArtPollReplyInfo longName: " << info.longName;
×
242

243
    return true;
×
244
}
245

246
bool ArtNetPacketizer::fillDMXdata(QByteArray const& data, QByteArray &dmx, quint32 &universe)
×
247
{
248
    if (data.isNull())
×
249
        return false;
×
250
    dmx.clear();
×
251
    //char sequence = data.at(12);
252
    //qDebug() << "Sequence: " << sequence;
253
    // char physical = data.at(13) // skipped
254
    universe = (data.at(15) << 8) + data.at(14);
×
255

256
    unsigned int msb = (data.at(16)&0xff);
×
257
    unsigned int lsb = (data.at(17)&0xff);
×
258
    int length = (msb << 8) | lsb;
×
259

260
    //qDebug() << "length: " << length;
261
    dmx.append(data.mid(18, length));
×
262
    return true;
×
263
}
264

265
bool ArtNetPacketizer::processTODdata(const QByteArray &data, quint32 &universe, QVariantMap &values)
×
266
{
267
    if (data.isNull() || data.length() < 28)
×
268
        return false;
×
269

270
    // 0 - 11 ArtNet header
271
    // 12 RDM version
272
    // 13 Port
273
    // 14 - 20 Spare
274
    // 21, 23 address
275
    universe = (data.at(21) << 8) + data.at(23);
×
276
    // 22 Command response
277
    // 24 - 25 UID total
278
    //quint16 uidTotal = (quint8(data.at(24)) << 8) + quint8(data.at(25));
279
    // 26 BlockCount (consider only when total > 200)
280
    // 27 UID count
281
    quint8 uidCount = quint8(data.at(27));
×
282

283
    qDebug() << "UID count:" << uidCount;
×
284

285
    for (int i = 0; i < uidCount; i++)
×
286
    {
287
        quint16 ESTAId;
288
        quint32 deviceId;
289
        QString UID = RDMProtocol::byteArrayToUID(data.mid(28 + (i * 6), 6), ESTAId, deviceId);
×
290
        qDebug() << "UID:" << UID;
×
291
        values.insert(QString("UID-%1").arg(i), UID);
×
292
    }
293
    values.insert("DISCOVERY_COUNT", uidCount);
×
294

295
    return true;
×
296
}
297

298
bool ArtNetPacketizer::processRDMdata(const QByteArray &data, quint32 &universe, QVariantMap &values)
×
299
{
300
    if (data.isNull() || data.length() < 24)
×
301
        return false;
×
302

303
    // 0 - 11 ArtNet header
304
    // 12 RDM version
305
    // 13 - 20 zero fillers
306
    // 21, 23 address
307
    universe = (data.at(21) << 8) + data.at(23);
×
308

309
    RDMProtocol rdm;
×
310
    return rdm.parsePacket(data.mid(24), values);
×
311
}
312

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

© 2026 Coveralls, Inc