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

OpenLightingProject / ola / 16900099157

12 Aug 2025 05:43AM UTC coverage: 45.72% (-0.02%) from 45.742%
16900099157

Pull #2016

github

web-flow
Merge c368ef6ae into eaf937e80
Pull Request #2016: Bump actions/checkout from 4 to 5

7586 of 17462 branches covered (43.44%)

22424 of 49046 relevant lines covered (45.72%)

51.77 hits per line

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

0.0
/plugins/kinet/kinet.cpp
1
/*
2
 * This program is free software; you can redistribute it and/or modify
3
 * it under the terms of the GNU General Public License as published by
4
 * the Free Software Foundation; either version 2 of the License, or
5
 * (at your option) any later version.
6
 *
7
 * This program is distributed in the hope that it will be useful,
8
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 * GNU Library General Public License for more details.
11
 *
12
 * You should have received a copy of the GNU General Public License
13
 * along with this program; if not, write to the Free Software
14
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
15
 *
16
 * kinet.cpp
17
 * Scratch pad for Kinet work
18
 * Copyright (C) 2010 Simon Newton
19
 */
20

21
#include <ola/Callback.h>
22
#include <ola/Logging.h>
23
#include <ola/base/Init.h>
24
#include <ola/io/SelectServer.h>
25
#include <ola/network/IPV4Address.h>
26
#include <ola/network/NetworkUtils.h>
27
#include <ola/network/Socket.h>
28
#include <ola/network/SocketAddress.h>
29

30
#include <iostream>
31
#include <string>
32

33
using std::cout;
34
using std::endl;
35
using std::string;
36
using ola::io::SelectServer;
37
using ola::network::IPV4Address;
38
using ola::network::IPV4SocketAddress;
39
using ola::network::LittleEndianToHost;
40
using ola::network::UDPSocket;
41

42

43
/*
44
 * The KiNet protocol appears to be little-endian. We write the constants as
45
 * they appear to a human and convert back and forth.
46
 */
47

48
// All packets seem to start with this number
49
const uint32_t KINET_MAGIC = 0x4adc0104;
50
// We haven't seen a non V1 protocol in the wild yet.
51
const uint16_t KINET_VERSION = 0x0001;
52
// No idea what this is, but we should send a poll reply when we see it
53
// const uint32_t KINET_DISCOVERY_COMMAND = 0x8988870a;
54

55
// KiNet packet types
56
typedef enum {
57
  KINET_POLL = 0x0001,
58
  KINET_POLL_REPLY = 0x0002,
59
  KINET_SET_IP = 0x0003,
60
  KINET_SET_UNIVERSE = 0x0005,
61
  KINET_SET_NAME = 0x0006,
62
  // KINET_?? = 0x000a;
63
  KINET_DMX = 0x0101,
64
  // KINET_?? = 0x0105;  // ?
65
  // KINET_PORTOUT = 0x0108;  // portout - is this the wrong endianness?
66
  // KINET_PORTOUT_SYNC = 0x0109;  // portout_sync
67
  // KINET_?? = 0x0201;  // seems to be a discovery packet, maybe for fixtures?
68
  // KINET_?? = 0x0203;  // get dmx address?
69
} kinet_packet_type;
70

71

72
/**
73
 * The KiNet header
74
 */
75
PACK(
76
struct kinet_header {
77
  uint32_t magic;
78
  uint16_t version;
79
  uint16_t type;  // see kinet_packet_type above
80
  uint32_t padding;  // always set to 0, seq #,
81
                     // most of the time it's 0,
82
                     // not implemented in most supplies
83
});
84

85

86
// A KiNet poll message
87
PACK(
88
struct kinet_poll {
89
  uint32_t command;  // ??, Seems to always be KINET_DISCOVERY_COMMAND
90
});
91

92

93
// A KiNet poll reply message
94
PACK(
95
struct kinet_poll_reply {
96
  uint32_t src_ip;
97
  uint8_t hw_address[6];  // mac address
98
  uint8_t  data[2];  // This contains non-0 data
99
  uint32_t serial;  // The node serial #
100
  uint32_t zero;
101
  uint8_t node_name[60];
102
  uint8_t node_label[31];
103
  uint16_t zero2;
104
});
105

106

107
// A KiNet Set IP Command.
108
// TODO(simon): Check what ip,mac dst this packet is sent to.
109
PACK(
110
struct kinet_set_ip {
111
  uint32_t something;  // ef be ad de
112
  uint8_t hw_address[6];  // The MAC address to match
113
  uint16_t something2;  // 05 67
114
  uint32_t new_ip;
115
});
116

117

118
// A KiNet Set Universe Command
119
PACK(
120
struct kinet_set_universe {
121
  uint32_t something;  // ef be ad de
122
  uint8_t universe;
123
  uint8_t zero[3];
124
});
125

126

127
// A KiNet Set Name Command
128
PACK(
129
struct kinet_set_name {
130
  uint32_t something;  // ef be ad de
131
  uint8_t new_name[31];  // Null terminated.
132
});
133

134

135
// A KiNet Get Address command
136
PACK(
137
struct kinet_get_address {
138
  uint32_t serial;
139
  uint32_t something;  // 41 00 12 00
140
});
141

142

143
// A KiNet DMX packet
144
PACK(
145
struct kinet_dmx {
146
  uint8_t port;  // should be set to 0 for v1
147
  uint8_t flags;  // set to 0
148
  uint16_t timerVal;  // set to 0
149
  uint32_t universe;
150
  uint8_t payload[513];  // payload inc start code
151
});
152

153

154
struct kinet_port_out_flags {
155
  uint16_t flags;
156
    // little endian
157
    // first bit is undefined  0:1;
158
    // second bit is for 16 bit data, set to 0  :1;
159
    // third is shall hold for sync packet :: 1;
160
};
161

162

163
struct kinet_port_out_sync {
164
  uint32_t padding;
165
};
166

167
// A KiNet DMX port out packet
168
PACK(
169
struct kinet_port_out {
170
  uint32_t universe;
171
  uint8_t port;        // 1- 16
172
  uint8_t pad;         // set to 0
173
  kinet_port_out_flags flags;
174
  uint16_t length;     // little endian
175
  uint16_t startCode;  // 0x0fff for chomASIC products, 0x0000 otherwise
176
  uint8_t payload[512];
177
});
178

179

180
// The full kinet packet
181
struct kinet_packet {
182
  struct kinet_header header;
183
  union {
184
    struct kinet_poll poll;
185
    struct kinet_poll_reply poll_reply;
186
  } data;
187
};
188

189

190
uint8_t peer0_0[] = {
191
  0x04, 0x01, 0xdc, 0x4a,  // magic number
192
  0x01, 0x00,  // version #
193
  0x02, 0x00,  // packet type (poll reply)
194
  0x00, 0x00, 0x00, 0x00,  // sequence
195
  0x0a, 0x00, 0x00, 0x9d,  // IP (was 192.168.1.207 in original sample)
196
  0x00, 0x0a, 0xc5, 0xff, 0xae, 0x01,  // mac address
197
  0x01, 0x00,  // ?
198
  0xff, 0xff, 0x00, 0x2d,  // serial #
199
  0x00, 0x00, 0x00, 0x00,  // padding
200
  // What follows is ascii text, with fields separated by new lines. Each field
201
  // is in the form /[MD#R]:.*/
202
  // It's unclear is this is a variable length field or not.
203
  0x4d, 0x3a,  // M:
204
  0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x4b, 0x69, 0x6e, 0x65, 0x74, 0x69, 0x63,
205
  0x73, 0x20, 0x49, 0x6e, 0x63, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x65,
206
  0x64,  // Color Kinetics cs Incorporated
207
  0x0a,  // \n
208
  0x44, 0x3a,  // D:
209
  0x50, 0x44, 0x53, 0x2d, 0x65,  // PDS-e
210
  0x0a,  // \n
211
  0x23, 0x3a,  // #:
212
  0x53, 0x46, 0x54, 0x2d, 0x30, 0x30, 0x30, 0x30, 0x36, 0x36, 0x2d, 0x30, 0x30,
213
  0x0a,  // SFT-000066-00
214
  0x52, 0x3a,  // R:
215
  0x30, 0x30,  // 00
216
  0x0a,  // \n
217
  0x00,
218
  // offset 92
219
  0x64, 0x73, 0x2d, 0x64, 0x61, 0x6e, 0x63, 0x65, 0x2d, 0x72, 0x65, 0x61, 0x72,
220
  0x00,  // ds-dance-rear - device name
221
  0x00, 0x95, 0x8c, 0xc7, 0xb6, 0x00,
222
  0x00,
223
  0xff, 0x00, 0x00,
224
  0xff, 0x00, 0x00,
225
  0xff, 0x00, 0x00,
226
  0xff, 0x00, 0x00 };
227

228

229
SelectServer ss;
230
UDPSocket udp_socket;
231

232
/**
233
 * Check if a packet is valid KiNet
234
 */
235
bool IsKiNet(const kinet_packet *packet, unsigned int size) {
×
236
  return (size > sizeof(struct kinet_header) &&
×
237
          KINET_MAGIC == LittleEndianToHost(packet->header.magic) &&
×
238
          KINET_VERSION == LittleEndianToHost(packet->header.version));
×
239
}
240

241

242
/**
243
 * Handle a KiNet poll packet
244
 */
245
void HandlePoll(const IPV4SocketAddress &source,
×
246
                OLA_UNUSED const kinet_packet &packet,
247
                OLA_UNUSED unsigned int size) {
248
  ssize_t r = udp_socket.SendTo(peer0_0, sizeof(peer0_0), source);
×
249
  OLA_INFO << "sent " << r << " bytes";
×
250
}
×
251

252

253
/**
254
 * Handle a KiNet DMX packet
255
 */
256
void HandleDmx(OLA_UNUSED const IPV4SocketAddress &source,
×
257
               OLA_UNUSED const kinet_packet &packet,
258
               OLA_UNUSED unsigned int size) {
259
}
×
260

261

262
void SocketReady() {
×
263
  kinet_packet packet;
×
264
  ssize_t data_read = sizeof(packet);
×
265
  IPV4SocketAddress source;
×
266

267
  udp_socket.RecvFrom(reinterpret_cast<uint8_t*>(&packet),
×
268
                      &data_read,
269
                      &source);
270
  if (IsKiNet(&packet, data_read)) {
×
271
    uint16_t command = LittleEndianToHost(packet.header.type);
×
272
    switch (command) {
×
273
      case KINET_POLL:
×
274
        OLA_INFO << "Got a poll packet";
×
275
        HandlePoll(source, packet, data_read);
×
276
        break;
277
      case KINET_DMX:
×
278
        OLA_INFO << "Got a DMX packet";
×
279
        HandleDmx(source, packet, data_read);
×
280
        break;
×
281
      default:
×
282
        OLA_WARN << "Unknown packet 0x" << std::hex << command;
×
283
    }
284
  } else {
285
    OLA_WARN << "Not a KiNet packet";
×
286
  }
287
}
×
288

289

290
/*
291
 * Main
292
 */
293
int main(int argc, char *argv[]) {
×
294
  ola::AppInit(&argc, argv, "", "Run the Kinet scratchpad.");
×
295

296
  udp_socket.SetOnData(ola::NewCallback(&SocketReady));
×
297
  if (!udp_socket.Init()) {
×
298
    OLA_WARN << "Failed to init";
×
299
    return 1;
×
300
  }
301
  if (!udp_socket.Bind(IPV4SocketAddress(IPV4Address::WildCard(), 6038))) {
×
302
    OLA_WARN << "Failed to bind";
×
303
    return 1;
×
304
  }
305
  if (!udp_socket.EnableBroadcast()) {
×
306
    OLA_WARN << "Failed to enable broadcast";
×
307
    return 1;
×
308
  }
309

310
  ss.AddReadDescriptor(&udp_socket);
×
311

312
  ss.Run();
×
313
  return 0;
×
314
}
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