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

mcallegari / qlcplus / 19144422256

06 Nov 2025 05:33PM UTC coverage: 34.256% (-0.1%) from 34.358%
19144422256

push

github

mcallegari
Back to 5.1.0 debug

17718 of 51723 relevant lines covered (34.26%)

19528.23 hits per line

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

91.84
/plugins/enttecwing/src/shortcutwing.cpp
1
/*
2
  Q Light Controller
3
  shortcutwing.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 <QHostAddress>
21
#include <QMessageBox>
22
#include <QByteArray>
23
#include <QUdpSocket>
24
#include <QString>
25
#include <QDebug>
26

27
#include "shortcutwing.h"
28

29
/****************************************************************************
30
 * Shortcut wing specifics
31
 ****************************************************************************/
32
/*
33
The ENTTEC Shortcut wing produces packets that contain
34
WING_SHORTCUT_BUTTON_SIZE bytes of button data. Each bit in these bytes
35
signifies the state of one button. Thus, each byte contains 8 buttons (except
36
the first one only 4 buttons), and they are in reversed order:
37

38
WING_SHORTCUT_BYTE_BUTTON +
39
                07  06  05  04  03  02  01  00
40
-----------------------------------------------
41
bit 0 : buttons 07, 15, 23, 31, 39, 47, 55, N/A
42
bit 1 : buttons 06, 14, 22, 30, 38, 46, 54, N/A
43
bit 2 : buttons 05, 13, 21, 29, 37, 45, 53, N/A
44
bit 3 : buttons 04, 12, 20, 28, 36, 44, 52, N/A
45
bit 4 : buttons 03, 11, 19, 27, 35, 43, 51, 59
46
bit 5 : buttons 02, 10, 18, 26, 34, 42, 50, 58
47
bit 6 : buttons 01, 09, 17, 25, 33, 41, 49, 57
48
bit 7 : buttons 00, 08, 16, 24, 32, 40, 48, 56
49

50
As it can be seen from the table above, the byte order is also reversed:
51

52
WING_SHORTCUT_BYTE_BUTTON + 0: Buttons 56 - 59 (4 buttons)
53
WING_SHORTCUT_BYTE_BUTTON + 1: Buttons 48 - 55 (8 buttons)
54
WING_SHORTCUT_BYTE_BUTTON + 2: Buttons 40 - 47 (8 buttons)
55
WING_SHORTCUT_BYTE_BUTTON + 3: Buttons 32 - 39 (8 buttons)
56
WING_SHORTCUT_BYTE_BUTTON + 4: Buttons 24 - 31 (8 buttons)
57
WING_SHORTCUT_BYTE_BUTTON + 5: Buttons 16 - 23 (8 buttons)
58
WING_SHORTCUT_BYTE_BUTTON + 6: Buttons 08 - 15 (8 buttons)
59
WING_SHORTCUT_BYTE_BUTTON + 7: Buttons 00 - 07 (8 buttons)
60
*/
61

62
#define WING_SHORTCUT_PAGE_UP   (1 << 3)
63
#define WING_SHORTCUT_PAGE_DOWN (1 << 2)
64

65
#define WING_SHORTCUT_BYTE_BUTTON 6
66
#define WING_SHORTCUT_BUTTON_SIZE 8
67

68
/** Should constitute up to 64 values (with the last 4 unused) */
69
#define WING_SHORTCUT_CHANNEL_COUNT 8 * WING_SHORTCUT_BUTTON_SIZE
70

71
#define WING_SHORTCUT_INPUT_VERSION 1
72
#define WING_SHORTCUT_INPUT_BYTE_VERSION 4
73
#define WING_SHORTCUT_INPUT_BYTE_PAGE 37
74

75
/****************************************************************************
76
 * Initialization
77
 ****************************************************************************/
78

79
ShortcutWing::ShortcutWing(QObject* parent, const QHostAddress& address,
1✔
80
                             const QByteArray& data)
1✔
81
    : Wing(parent, address, data)
1✔
82
{
83
    m_values = QByteArray(WING_SHORTCUT_CHANNEL_COUNT, 0);
1✔
84

85
    /* Take initial values from the first received datagram packet.
86
       The plugin hasn't yet connected to valueChanged() signal, so this
87
       won't cause any input events. */
88
    parseData(data);
1✔
89
    sendPageData();
1✔
90
}
1✔
91

92
ShortcutWing::~ShortcutWing()
2✔
93
{
94
}
2✔
95

96
/****************************************************************************
97
 * Wing data
98
 ****************************************************************************/
99

100
QString ShortcutWing::name() const
3✔
101
{
102
    QString name("Shortcut");
3✔
103
    name += QString(" ") + tr("at") + QString(" ");
3✔
104
    name += m_address.toString();
3✔
105

106
    return name;
3✔
107
}
×
108

109
/****************************************************************************
110
 * Input data
111
 ****************************************************************************/
112

113
void ShortcutWing::parseData(const QByteArray& data)
122✔
114
{
115
    /* Check if page buttons were pressed and act accordingly */
116
    applyPageButtons(data);
122✔
117

118
    /* Check that we can get all channels from the packet */
119
    int size = WING_SHORTCUT_BYTE_BUTTON + WING_SHORTCUT_BUTTON_SIZE;
122✔
120
    if (data.size() < size)
122✔
121
    {
122
        qWarning() << Q_FUNC_INFO << "Expected at least" << size
2✔
123
                   << "bytes for buttons but got only" << data.size();
1✔
124
        return;
1✔
125
    }
126

127
    /* Read the state of each button */
128
    for (int byte = size - 1; byte >= WING_SHORTCUT_BYTE_BUTTON; byte--)
1,089✔
129
    {
130
        /* Each byte has 8 button values as binary bits */
131
        for (int bit = 7; bit >= 0; bit--)
8,228✔
132
        {
133
            int key;
134
            uchar value;
135

136
            key = (size - byte - 1) * 8;
7,381✔
137
            key += (7 - bit);
7,381✔
138

139
            /* There's only 60 channels in a Shortcut Wing, but
140
               the data packet contains 64 values. So don't read
141
               the extra 4 bits. */
142
            if (key > 59)
7,381✔
143
                break;
121✔
144

145
            /* 0 = button down, 1 = button up */
146
            if ((data[byte] & (1 << bit)) == 0)
7,260✔
147
                value = UCHAR_MAX;
504✔
148
            else
149
                value = 0;
6,756✔
150

151
            setCacheValue(key, value);
7,260✔
152
        }
153
    }
154
}
155

156
void ShortcutWing::applyPageButtons(const QByteArray& data)
122✔
157
{
158
    /* Check that there's enough data for flags */
159
    if (data.size() < WING_BYTE_FLAGS + 1)
122✔
160
        return;
×
161

162
    if ((data[WING_BYTE_FLAGS] & WING_SHORTCUT_PAGE_UP) == 0)
122✔
163
    {
164
        nextPage();
121✔
165
        sendPageData();
121✔
166
    }
167
    else if ((data[WING_BYTE_FLAGS] & WING_SHORTCUT_PAGE_DOWN) == 0)
1✔
168
    {
169
        previousPage();
×
170
        sendPageData();
×
171
    }
172
}
173

174
void ShortcutWing::sendPageData()
122✔
175
{
176
    QByteArray sendData(42, char(0));
122✔
177
    sendData.replace(0, sizeof(WING_HEADER_INPUT), WING_HEADER_INPUT);
122✔
178
    sendData[WING_SHORTCUT_INPUT_BYTE_VERSION] = WING_SHORTCUT_INPUT_VERSION;
122✔
179
    sendData[WING_SHORTCUT_INPUT_BYTE_PAGE] = toBCD(page());
122✔
180

181
    QUdpSocket sock(this);
122✔
182
    sock.writeDatagram(sendData, address(), Wing::UDPPort);
122✔
183
}
122✔
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