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

OpenLightingProject / ola / 5304966656

18 Jun 2023 06:21PM UTC coverage: 45.16%. First build
5304966656

Pull #1860

github

web-flow
Merge 788ce57e2 into 80bf78d6a
Pull Request #1860: Master resync 0.10

7601 of 17582 branches covered (43.23%)

1 of 1 new or added line in 1 file covered. (100.0%)

21408 of 47405 relevant lines covered (45.16%)

85.25 hits per line

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

85.84
/common/rdm/RDMCommand.cpp
1
/*
2
 * This library is free software; you can redistribute it and/or
3
 * modify it under the terms of the GNU Lesser General Public
4
 * License as published by the Free Software Foundation; either
5
 * version 2.1 of the License, or (at your option) any later version.
6
 *
7
 * This library 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 GNU
10
 * Lesser General Public License for more details.
11
 *
12
 * You should have received a copy of the GNU Lesser General Public
13
 * License along with this library; if not, write to the Free Software
14
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15
 *
16
 * RDMCommand.cpp
17
 * The RDMCommand class
18
 * Copyright (C) 2010 Simon Newton
19
 */
20

21
/**
22
 * @addtogroup rdm_command
23
 * @{
24
 * @file RDMCommand.cpp
25
 * @}
26
 */
27

28
#include <string.h>
29
#include <string>
30
#include "ola/Logging.h"
31
#include "ola/network/NetworkUtils.h"
32
#include "ola/rdm/RDMCommand.h"
33
#include "ola/rdm/UID.h"
34
#include "ola/strings/Format.h"
35
#include "ola/util/Utils.h"
36

37
namespace ola {
38
namespace rdm {
39

40
using std::string;
41
using ola::strings::ToHex;
42
using ola::utils::JoinUInt8;
43
using ola::utils::SplitUInt16;
44

45
// Internal Helper Functions
46
namespace {
47

48
/**
49
 * @brief Guess the CommandClass of an RDM message.
50
 * @param data a pointer to the RDM message (excluding the start code)
51
 * @param length length of the RDM data
52
 * @returns A RDMCommandClass value, which is set to INVALID_COMMAND if we
53
 * couldn't determine the message type.
54
 *
55
 * This doesn't perform any data checking (that's left to the Inflate* methods).
56
 */
57
RDMCommand::RDMCommandClass GuessMessageType(const uint8_t *data,
9✔
58
                                             unsigned int length) {
59
  static const unsigned int COMMAND_CLASS_OFFSET = 19;
9✔
60
  if (!data || length < COMMAND_CLASS_OFFSET + 1) {
9✔
61
    return RDMCommand::INVALID_COMMAND;
62
  }
63

64
  switch (data[COMMAND_CLASS_OFFSET]) {
7✔
65
    case RDMCommand::GET_COMMAND:
7✔
66
    case RDMCommand::GET_COMMAND_RESPONSE:
7✔
67
    case RDMCommand::SET_COMMAND:
7✔
68
    case RDMCommand::SET_COMMAND_RESPONSE:
7✔
69
    case RDMCommand::DISCOVER_COMMAND:
7✔
70
    case RDMCommand::DISCOVER_COMMAND_RESPONSE:
7✔
71
      return static_cast<RDMCommand::RDMCommandClass>(
7✔
72
          data[COMMAND_CLASS_OFFSET]);
7✔
73
    default:
74
      return RDMCommand::INVALID_COMMAND;
75
  }
76
}
77
}  // namespace
78

79
/**
80
 * @addtogroup rdm_command
81
 * @{
82
 */
83

84
RDMCommand::RDMCommand(const UID &source,
585✔
85
                       const UID &destination,
86
                       uint8_t transaction_number,
87
                       uint8_t port_id,
88
                       uint8_t message_count,
89
                       uint16_t sub_device,
90
                       uint16_t param_id,
91
                       const uint8_t *data,
92
                       unsigned int length):
585✔
93
    m_port_id(port_id),
585✔
94
    m_source(source),
585✔
95
    m_destination(destination),
585✔
96
    m_transaction_number(transaction_number),
585✔
97
    m_message_count(message_count),
585✔
98
    m_sub_device(sub_device),
585✔
99
    m_param_id(param_id),
585✔
100
    m_data(NULL),
585✔
101
    m_data_length(length) {
585✔
102
  SetParamData(data, length);
585✔
103
}
585✔
104

105

106
RDMCommand::~RDMCommand() {
1,170✔
107
  if (m_data) {
1,170✔
108
    delete[] m_data;
470✔
109
  }
110
}
1,170✔
111

112
string RDMCommand::ToString() const {
2✔
113
  std::ostringstream str;
2✔
114
  str << m_source << " -> " << m_destination << ", Trans # "
2✔
115
      << static_cast<int>(m_transaction_number) << ", Port ID "
2✔
116
      << static_cast<int>(m_port_id) << ", Msg Cnt "
2✔
117
      << static_cast<int>(m_message_count) << ", SubDevice " << m_sub_device
2✔
118
      << ", Cmd Class " << CommandClass() << ", Param ID " << m_param_id
2✔
119
      << ", Data Len " << m_data_length;
2✔
120
  str << ", Data ";
2✔
121
  for (unsigned int i = 0 ; i < m_data_length; i++) {
2✔
122
    str << ToHex(m_data[i], false) << " ";
×
123
  }
124
  return str.str();
4✔
125
}
2✔
126

127
bool RDMCommand::operator==(const RDMCommand &other) const {
84✔
128
  if (SourceUID() == other.SourceUID() &&
84✔
129
      DestinationUID() == other.DestinationUID() &&
84✔
130
      TransactionNumber() == other.TransactionNumber() &&
84✔
131
      MessageCount() == other.MessageCount() &&
84✔
132
      SubDevice() == other.SubDevice() &&
168✔
133
      CommandClass() == other.CommandClass() &&
84✔
134
      ParamId() == other.ParamId() &&
168✔
135
      ParamDataSize() == other.ParamDataSize()) {
84✔
136
    return 0 == memcmp(ParamData(), other.ParamData(), ParamDataSize());
84✔
137
  }
138
  return false;
139
}
140

141
RDMCommand *RDMCommand::Inflate(const uint8_t *data, unsigned int length) {
9✔
142
  RDMCommandClass command_class = GuessMessageType(data, length);
9✔
143

144
  RDMStatusCode status_code = RDM_COMPLETED_OK;
9✔
145
  switch (command_class) {
9✔
146
    case RDMCommand::GET_COMMAND:
2✔
147
    case RDMCommand::SET_COMMAND:
2✔
148
      return RDMRequest::InflateFromData(data, length);
2✔
149
    case RDMCommand::GET_COMMAND_RESPONSE:
1✔
150
    case RDMCommand::SET_COMMAND_RESPONSE:
1✔
151
      return RDMResponse::InflateFromData(data, length, &status_code);
1✔
152
    case RDMCommand::DISCOVER_COMMAND:
3✔
153
      return RDMDiscoveryRequest::InflateFromData(data, length);
3✔
154
    case RDMCommand::DISCOVER_COMMAND_RESPONSE:
1✔
155
      return RDMDiscoveryResponse::InflateFromData(data, length);
1✔
156
    case RDMCommand::INVALID_COMMAND:
157
      return NULL;
158
  }
159
  return NULL;
160
}
161

162
uint8_t RDMCommand::MessageLength() const {
115✔
163
  // The size of packet including start code, excluding checksum
164
  return sizeof(RDMCommandHeader) + m_data_length + 1;
115✔
165
}
166

167

168
/**
169
 * Set the parameter data
170
 */
171
void RDMCommand::SetParamData(const uint8_t *data, unsigned int length) {
585✔
172
  m_data_length = length;
585✔
173
  if (m_data_length > 0 && data != NULL) {
585✔
174
    if (m_data) {
235✔
175
      delete[] m_data;
×
176
    }
177

178
    m_data = new uint8_t[m_data_length];
235✔
179
    memcpy(m_data, data, m_data_length);
235✔
180
  }
181
}
585✔
182

183

184
/*
185
 * Convert a block of RDM data to an RDMCommand object.
186
 * The data must not include the RDM start code.
187
 * @param data the raw RDM data, starting from the sub-start-code
188
 * @param length the length of the data
189
 * @param command_header the RDMCommandHeader struct to copy the data to
190
 * @return a RDMStatusCode
191
 */
192
RDMStatusCode RDMCommand::VerifyData(const uint8_t *data,
51✔
193
                                     size_t length,
194
                                     RDMCommandHeader *command_header) {
195
  if (length < sizeof(RDMCommandHeader)) {
51✔
196
    OLA_WARN << "RDM message is too small, needs to be at least "
12✔
197
             << sizeof(RDMCommandHeader) << ", was " << length;
6✔
198
    return RDM_PACKET_TOO_SHORT;
6✔
199
  }
200

201
  if (!data) {
45✔
202
    OLA_WARN << "RDM data was null";
1✔
203
    return RDM_INVALID_RESPONSE;
1✔
204
  }
205

206
  memcpy(reinterpret_cast<uint8_t*>(command_header),
44✔
207
         data,
208
         sizeof(*command_header));
209

210
  if (command_header->sub_start_code != SUB_START_CODE) {
44✔
211
    OLA_WARN << "Sub start code mismatch, was "
×
212
             << ToHex(command_header->sub_start_code) << ", required "
×
213
             << ToHex(SUB_START_CODE);
×
214
    return RDM_WRONG_SUB_START_CODE;
×
215
  }
216

217
  unsigned int message_length = command_header->message_length;
44✔
218
  if (length < message_length + 1) {
44✔
219
    OLA_WARN << "RDM message is too small, needs to be "
×
220
             << message_length + 1 << ", was " << length;
×
221
    return RDM_PACKET_LENGTH_MISMATCH;
×
222
  }
223

224
  uint16_t checksum = CalculateChecksum(data, message_length - 1);
44✔
225
  uint16_t actual_checksum = JoinUInt8(data[message_length - 1],
44✔
226
                                       data[message_length]);
44✔
227

228
  if (actual_checksum != checksum) {
44✔
229
    OLA_WARN << "RDM checksum mismatch, was " << actual_checksum
8✔
230
             << " but was supposed to be " << checksum;
4✔
231
    return RDM_CHECKSUM_INCORRECT;
4✔
232
  }
233

234
  // check param length is valid here
235
  unsigned int block_size = length - sizeof(RDMCommandHeader) - 2;
40✔
236
  if (command_header->param_data_length > block_size) {
40✔
237
    OLA_WARN << "Param length "
8✔
238
             << static_cast<int>(command_header->param_data_length)
4✔
239
             << " exceeds remaining RDM message size of " << block_size;
4✔
240
    return RDM_PARAM_LENGTH_MISMATCH;
4✔
241
  }
242
  return RDM_COMPLETED_OK;
243
}
244

245

246
/*
247
 * Calculate the checksum of this packet
248
 */
249
uint16_t RDMCommand::CalculateChecksum(const uint8_t *data,
44✔
250
                                       unsigned int packet_length) {
251
  unsigned int checksum_value = START_CODE;
44✔
252
  for (unsigned int i = 0; i < packet_length; i++) {
1,180✔
253
    checksum_value += data[i];
1,136✔
254
  }
255
  return static_cast<uint16_t>(checksum_value);
44✔
256
}
257

258

259
/*
260
 * Convert the Command Class int to an enum
261
 */
262
RDMCommand::RDMCommandClass RDMCommand::ConvertCommandClass(
36✔
263
    uint8_t command_class) {
264
  switch (command_class) {
36✔
265
    case DISCOVER_COMMAND:
266
      return DISCOVER_COMMAND;
267
    case DISCOVER_COMMAND_RESPONSE:
268
      return DISCOVER_COMMAND_RESPONSE;
269
    case GET_COMMAND:
270
      return GET_COMMAND;
271
    case GET_COMMAND_RESPONSE:
272
      return GET_COMMAND_RESPONSE;
273
    case SET_COMMAND:
274
      return SET_COMMAND;
275
    case SET_COMMAND_RESPONSE:
276
      return SET_COMMAND_RESPONSE;
277
    default:
278
      return INVALID_COMMAND;
279
  }
280
}
281

282
RDMRequest::RDMRequest(const UID &source,
402✔
283
                       const UID &destination,
284
                       uint8_t transaction_number,
285
                       uint8_t port_id,
286
                       uint16_t sub_device,
287
                       RDMCommandClass command_class,
288
                       uint16_t param_id,
289
                       const uint8_t *data,
290
                       unsigned int length,
291
                       const OverrideOptions &options)
402✔
292
    : RDMCommand(source, destination, transaction_number, port_id,
293
                 options.message_count, sub_device, param_id, data, length),
402✔
294
      m_override_options(options),
402✔
295
      m_command_class(command_class) {
402✔
296
}
402✔
297

298
bool RDMRequest::IsDUB() const {
69✔
299
  return (CommandClass() == ola::rdm::RDMCommand::DISCOVER_COMMAND &&
69✔
300
          ParamId() == ola::rdm::PID_DISC_UNIQUE_BRANCH);
34✔
301
}
302

303
uint8_t RDMRequest::SubStartCode() const {
107✔
304
  return m_override_options.sub_start_code;
107✔
305
}
306

307
uint8_t RDMRequest::MessageLength() const {
106✔
308
  if (m_override_options.has_message_length) {
106✔
309
    return m_override_options.message_length;
3✔
310
  } else {
311
    return RDMCommand::MessageLength();
103✔
312
  }
313
}
314

315
uint16_t RDMRequest::Checksum(uint16_t checksum) const {
107✔
316
  return m_override_options.has_checksum ?
107✔
317
      m_override_options.checksum : checksum;
107✔
318
}
319

320
RDMRequest* RDMRequest::InflateFromData(const uint8_t *data,
14✔
321
                                        unsigned int length) {
322
  RDMCommandHeader command_message;
14✔
323
  RDMStatusCode status_code = VerifyData(data, length, &command_message);
14✔
324
  if (status_code != RDM_COMPLETED_OK) {
14✔
325
    return NULL;
326
  }
327

328
  UID source_uid(command_message.source_uid);
7✔
329
  UID destination_uid(command_message.destination_uid);
7✔
330
  uint16_t sub_device = JoinUInt8(command_message.sub_device[0],
7✔
331
                                  command_message.sub_device[1]);
7✔
332
  uint16_t param_id = JoinUInt8(command_message.param_id[0],
7✔
333
                                command_message.param_id[1]);
7✔
334
  RDMCommandClass command_class = ConvertCommandClass(
14✔
335
    command_message.command_class);
7✔
336

337
  OverrideOptions options;
7✔
338
  options.sub_start_code = command_message.sub_start_code;
7✔
339
  options.message_length = command_message.message_length;
7✔
340
  options.message_count = command_message.message_count;
7✔
341

342
  switch (command_class) {
7✔
343
    case DISCOVER_COMMAND:
×
344
      return new RDMDiscoveryRequest(
×
345
          source_uid,
346
          destination_uid,
347
          command_message.transaction_number,  // transaction #
×
348
          command_message.port_id,  // port id
×
349
          sub_device,
350
          param_id,
351
          data + sizeof(RDMCommandHeader),
352
          command_message.param_data_length,  // data length
×
353
          options);
×
354
    case GET_COMMAND:
4✔
355
      return new RDMGetRequest(
4✔
356
          source_uid,
357
          destination_uid,
358
          command_message.transaction_number,  // transaction #
4✔
359
          command_message.port_id,  // port id
4✔
360
          sub_device,
361
          param_id,
362
          data + sizeof(RDMCommandHeader),
363
          command_message.param_data_length,  // data length
4✔
364
          options);
4✔
365
    case SET_COMMAND:
2✔
366
      return new RDMSetRequest(
2✔
367
          source_uid,
368
          destination_uid,
369
          command_message.transaction_number,  // transaction #
2✔
370
          command_message.port_id,  // port id
2✔
371
          sub_device,
372
          param_id,
373
          data + sizeof(RDMCommandHeader),
374
          command_message.param_data_length,  // data length
2✔
375
          options);
2✔
376
    default:
1✔
377
      OLA_WARN << "Expected a RDM request command but got "
3✔
378
               << ToHex(command_class) << ", from " << source_uid << " to "
2✔
379
               << destination_uid << ", TN "
1✔
380
               << static_cast<int>(command_message.transaction_number);
1✔
381
      return NULL;
1✔
382
  }
383
}
384

385
RDMResponse* RDMResponse::InflateFromData(const uint8_t *data,
33✔
386
                                          size_t length,
387
                                          RDMStatusCode *status_code,
388
                                          const RDMRequest *request) {
389
  RDMCommandHeader command_message;
33✔
390
  *status_code = VerifyData(data, length, &command_message);
33✔
391
  if (*status_code != RDM_COMPLETED_OK) {
33✔
392
    return NULL;
393
  }
394

395
  UID source_uid(command_message.source_uid);
25✔
396
  UID destination_uid(command_message.destination_uid);
25✔
397
  uint16_t sub_device = JoinUInt8(command_message.sub_device[0],
25✔
398
                                  command_message.sub_device[1]);
25✔
399
  RDMCommandClass command_class = ConvertCommandClass(
50✔
400
    command_message.command_class);
25✔
401

402
  if (request) {
25✔
403
    // check dest uid
404
    if (request->SourceUID() != destination_uid) {
9✔
405
      OLA_WARN << "The destination UID in the response doesn't match, got "
×
406
               << destination_uid << ", expected " << request->SourceUID();
×
407
      *status_code = RDM_DEST_UID_MISMATCH;
×
408
      return NULL;
×
409
    }
410

411
    // check src uid
412
    if (request->DestinationUID() != source_uid) {
9✔
413
      OLA_WARN << "The source UID in the response doesn't match, got "
×
414
               << source_uid << ", expected " << request->DestinationUID();
×
415
      *status_code = RDM_SRC_UID_MISMATCH;
×
416
      return NULL;
×
417
    }
418

419
    // check transaction #
420
    if (command_message.transaction_number != request->TransactionNumber()) {
9✔
421
      OLA_WARN << "Transaction numbers don't match, got "
2✔
422
               << static_cast<int>(command_message.transaction_number)
1✔
423
               << ", expected "
1✔
424
               << static_cast<int>(request->TransactionNumber());
1✔
425
      *status_code = RDM_TRANSACTION_MISMATCH;
1✔
426
      return NULL;
1✔
427
    }
428

429
    // check subdevice, but ignore if request was for all sub devices or
430
    // QUEUED_MESSAGE
431
    if (sub_device != request->SubDevice() &&
8✔
432
        request->SubDevice() != ALL_RDM_SUBDEVICES &&
8✔
433
         request->ParamId() != PID_QUEUED_MESSAGE) {
1✔
434
      OLA_WARN << "Sub device didn't match, got " << sub_device
2✔
435
               << ", expected " << request->SubDevice();
1✔
436
      *status_code = RDM_SUB_DEVICE_MISMATCH;
1✔
437
      return NULL;
1✔
438
    }
439

440
    // check command class
441
    if (request->CommandClass() == GET_COMMAND &&
11✔
442
        command_class != GET_COMMAND_RESPONSE &&
7✔
443
        request->ParamId() != PID_QUEUED_MESSAGE) {
×
444
      OLA_WARN << "Expected GET_COMMAND_RESPONSE, got "
×
445
               << ToHex(command_class);
×
446
      *status_code = RDM_COMMAND_CLASS_MISMATCH;
×
447
      return NULL;
×
448
    }
449

450
    if (request->CommandClass() == SET_COMMAND &&
7✔
451
        command_class != SET_COMMAND_RESPONSE) {
452
      OLA_WARN << "Expected SET_COMMAND_RESPONSE, got "
×
453
               << ToHex(command_class);
×
454
      *status_code = RDM_COMMAND_CLASS_MISMATCH;
×
455
      return NULL;
×
456
    }
457

458
    if (request->CommandClass() == DISCOVER_COMMAND &&
7✔
459
        command_class != DISCOVER_COMMAND_RESPONSE) {
460
      OLA_WARN << "Expected DISCOVER_COMMAND_RESPONSE, got "
×
461
               << ToHex(command_class);
×
462
      *status_code = RDM_COMMAND_CLASS_MISMATCH;
×
463
      return NULL;
×
464
    }
465
  }
466

467
  // check response type
468
  if (command_message.port_id > ACK_OVERFLOW) {
23✔
469
    OLA_WARN << "Response type isn't valid, got "
×
470
             << static_cast<int>(command_message.port_id);
×
471
    *status_code = RDM_INVALID_RESPONSE_TYPE;
×
472
    return NULL;
×
473
  }
474

475
  uint16_t param_id = JoinUInt8(command_message.param_id[0],
23✔
476
                                command_message.param_id[1]);
23✔
477
  uint8_t return_transaction_number = command_message.transaction_number;
23✔
478

479
  switch (command_class) {
23✔
480
    case DISCOVER_COMMAND_RESPONSE:
6✔
481
      *status_code = RDM_COMPLETED_OK;
6✔
482
      return new RDMDiscoveryResponse(
6✔
483
          source_uid,
484
          destination_uid,
485
          return_transaction_number,  // transaction #
486
          command_message.port_id,  // port id
6✔
487
          command_message.message_count,  // message count
6✔
488
          sub_device,
489
          param_id,
490
          data + sizeof(RDMCommandHeader),
491
          command_message.param_data_length);  // data length
6✔
492
    case GET_COMMAND_RESPONSE:
15✔
493
      *status_code = RDM_COMPLETED_OK;
15✔
494
      return new RDMGetResponse(
15✔
495
          source_uid,
496
          destination_uid,
497
          return_transaction_number,  // transaction #
498
          command_message.port_id,  // port id
15✔
499
          command_message.message_count,  // message count
15✔
500
          sub_device,
501
          param_id,
502
          data + sizeof(RDMCommandHeader),
503
          command_message.param_data_length);  // data length
15✔
504
    case SET_COMMAND_RESPONSE:
×
505
      *status_code = RDM_COMPLETED_OK;
×
506
      return new RDMSetResponse(
×
507
          source_uid,
508
          destination_uid,
509
          return_transaction_number,  // transaction #
510
          command_message.port_id,  // port id
×
511
          command_message.message_count,  // message count
×
512
          sub_device,
513
          param_id,
514
          data + sizeof(RDMCommandHeader),
515
          command_message.param_data_length);  // data length
×
516
    default:
2✔
517
      OLA_WARN << "Command class isn't valid, got " << ToHex(command_class)
4✔
518
               << ", from " << source_uid << " to " << destination_uid
2✔
519
               << ", TN " << static_cast<int>(return_transaction_number);
2✔
520
      *status_code = RDM_INVALID_COMMAND_CLASS;
2✔
521
      return NULL;
2✔
522
  }
523
}
524

525
RDMResponse* RDMResponse::CombineResponses(const RDMResponse *response1,
9✔
526
                                           const RDMResponse *response2) {
527
  unsigned int combined_length = response1->ParamDataSize() +
9✔
528
    response2->ParamDataSize();
9✔
529
  // do some sort of checking
530
  if (combined_length > MAX_OVERFLOW_SIZE) {
9✔
531
    OLA_WARN << "ACK_OVERFLOW buffer size hit! Limit is " << MAX_OVERFLOW_SIZE
×
532
             << ", request size is " << combined_length;
×
533
    return NULL;
×
534
  } else if (response1->SourceUID() != response2->SourceUID()) {
9✔
535
    OLA_WARN << "Source UIDs don't match, got " << response1->SourceUID()
2✔
536
             << " and " << response2->SourceUID();
1✔
537
    return NULL;
1✔
538
  }
539

540
  uint8_t *combined_data = new uint8_t[combined_length];
8✔
541
  memcpy(combined_data, response1->ParamData(), response1->ParamDataSize());
8✔
542
  memcpy(combined_data + response1->ParamDataSize(),
8✔
543
         response2->ParamData(),
8✔
544
         response2->ParamDataSize());
8✔
545

546
  RDMResponse *response = NULL;
8✔
547
  if (response1->CommandClass() == GET_COMMAND_RESPONSE &&
13✔
548
      response2->CommandClass() == GET_COMMAND_RESPONSE) {
5✔
549
    response = new RDMGetResponse(
8✔
550
        response1->SourceUID(),
551
        response1->DestinationUID(),
552
        response1->TransactionNumber(),
4✔
553
        RDM_ACK,
554
        response2->MessageCount(),
4✔
555
        response1->SubDevice(),
4✔
556
        response1->ParamId(),
4✔
557
        combined_data,
558
        combined_length);
4✔
559
  } else if (response1->CommandClass() == SET_COMMAND_RESPONSE &&
7✔
560
             response2->CommandClass() == SET_COMMAND_RESPONSE) {
3✔
561
    response = new RDMSetResponse(
4✔
562
        response1->SourceUID(),
563
        response1->DestinationUID(),
564
        response1->TransactionNumber(),
2✔
565
        RDM_ACK,
566
        response2->MessageCount(),
2✔
567
        response1->SubDevice(),
2✔
568
        response1->ParamId(),
2✔
569
        combined_data,
570
        combined_length);
2✔
571
  } else {
572
    OLA_WARN << "Expected a pair of RDM response commands but got "
6✔
573
             << ToHex(response1->CommandClass()) << " and "
2✔
574
             << ToHex(response2->CommandClass());
2✔
575
  }
576
  delete[] combined_data;
8✔
577
  return response;
8✔
578
}
579

580
// Helper functions follow
581

582

583
RDMResponse *NackWithReason(const RDMRequest *request,
61✔
584
                            rdm_nack_reason reason_enum,
585
                            uint8_t outstanding_messages) {
586
  uint16_t reason = ola::network::HostToNetwork(
61✔
587
      static_cast<uint16_t>(reason_enum));
61✔
588
  return GetResponseFromData(request,
61✔
589
                             reinterpret_cast<uint8_t*>(&reason),
590
                             sizeof(reason),
591
                             RDM_NACK_REASON,
592
                             outstanding_messages);
61✔
593
}
594

595
RDMResponse *NackWithReason(const RDMResponse *response,
1✔
596
                            rdm_nack_reason reason_enum) {
597
  uint16_t reason = ola::network::HostToNetwork(
1✔
598
      static_cast<uint16_t>(reason_enum));
1✔
599
  return new RDMResponse(response->SourceUID(),
1✔
600
                         response->DestinationUID(),
601
                         response->TransactionNumber(),
1✔
602
                         RDM_NACK_REASON,
603
                         response->MessageCount(),
1✔
604
                         response->SubDevice(),
1✔
605
                         response->CommandClass(),
1✔
606
                         response->ParamId(),
1✔
607
                         reinterpret_cast<uint8_t*>(&reason),
608
                         sizeof(reason));
1✔
609
}
610

611
RDMResponse *GetResponseFromData(const RDMRequest *request,
114✔
612
                                 const uint8_t *data,
613
                                 unsigned int length,
614
                                 rdm_response_type type,
615
                                 uint8_t outstanding_messages) {
616
  // We can reuse GetResponseWithPid
617
  return GetResponseWithPid(request,
114✔
618
                            request->ParamId(),
114✔
619
                            data,
620
                            length,
621
                            type,
622
                            outstanding_messages);
114✔
623
}
624

625
RDMResponse *GetResponseWithPid(const RDMRequest *request,
120✔
626
                                uint16_t pid,
627
                                const uint8_t *data,
628
                                unsigned int length,
629
                                uint8_t type,
630
                                uint8_t outstanding_messages) {
631
  switch (request->CommandClass()) {
120✔
632
    case RDMCommand::GET_COMMAND:
88✔
633
      // coverity[SWAPPED_ARGUMENTS]
634
      return new RDMGetResponse(
88✔
635
        request->DestinationUID(),
636
        request->SourceUID(),
637
        request->TransactionNumber(),
88✔
638
        type,
639
        outstanding_messages,
640
        request->SubDevice(),
88✔
641
        pid,
642
        data,
643
        length);
88✔
644
    case RDMCommand::SET_COMMAND:
29✔
645
      // coverity[SWAPPED_ARGUMENTS]
646
      return new RDMSetResponse(
29✔
647
        request->DestinationUID(),
648
        request->SourceUID(),
649
        request->TransactionNumber(),
29✔
650
        type,
651
        outstanding_messages,
652
        request->SubDevice(),
29✔
653
        pid,
654
        data,
655
        length);
29✔
656
    case RDMCommand::DISCOVER_COMMAND:
3✔
657
      // coverity[SWAPPED_ARGUMENTS]
658
      return new RDMDiscoveryResponse(
3✔
659
        request->DestinationUID(),
660
        request->SourceUID(),
661
        request->TransactionNumber(),
3✔
662
        type,
663
        outstanding_messages,
664
        request->SubDevice(),
3✔
665
        pid,
666
        data,
667
        length);
3✔
668
     default:
669
      return NULL;
670
  }
671
}
672

673

674
/**
675
 * @brief Inflate a discovery request.
676
 */
677
RDMDiscoveryRequest* RDMDiscoveryRequest::InflateFromData(
3✔
678
    const uint8_t *data,
679
    unsigned int length) {
680
  RDMCommandHeader command_message;
3✔
681
  RDMStatusCode code = VerifyData(data, length, &command_message);
3✔
682
  if (code != RDM_COMPLETED_OK) {
3✔
683
    return NULL;
684
  }
685

686
  uint16_t sub_device = JoinUInt8(command_message.sub_device[0],
3✔
687
                                  command_message.sub_device[1]);
3✔
688
  uint16_t param_id = JoinUInt8(command_message.param_id[0],
3✔
689
                                command_message.param_id[1]);
3✔
690
  RDMCommandClass command_class = ConvertCommandClass(
6✔
691
    command_message.command_class);
3✔
692

693
  OverrideOptions options;
3✔
694
  options.sub_start_code = command_message.sub_start_code;
3✔
695
  options.message_length = command_message.message_length;
3✔
696
  options.message_count = command_message.message_count;
3✔
697

698
  if (command_class == DISCOVER_COMMAND) {
3✔
699
    return new RDMDiscoveryRequest(
3✔
700
        UID(command_message.source_uid),
3✔
701
        UID(command_message.destination_uid),
6✔
702
        command_message.transaction_number,  // transaction #
3✔
703
        command_message.port_id,  // port id
3✔
704
        sub_device,
705
        param_id,
706
        data + sizeof(RDMCommandHeader),
707
        command_message.param_data_length,  // data length
3✔
708
        options);
6✔
709
  } else {
710
    OLA_WARN << "Expected a RDM discovery request but got " << command_class;
×
711
    return NULL;
×
712
  }
713
}
714

715

716
/*
717
 * Create a new DUB request object.
718
 */
719
RDMDiscoveryRequest *NewDiscoveryUniqueBranchRequest(
17✔
720
    const UID &source,
721
    const UID &lower,
722
    const UID &upper,
723
    uint8_t transaction_number,
724
    uint8_t port_id) {
725
  uint8_t param_data[UID::UID_SIZE * 2];
17✔
726
  unsigned int length = sizeof(param_data);
17✔
727
  lower.Pack(param_data, length);
17✔
728
  upper.Pack(param_data + UID::UID_SIZE, length - UID::UID_SIZE);
17✔
729
  return new RDMDiscoveryRequest(source,
17✔
730
                                 UID::AllDevices(),
17✔
731
                                 transaction_number,
732
                                 port_id,
733
                                 ROOT_RDM_DEVICE,
734
                                 PID_DISC_UNIQUE_BRANCH,
735
                                 param_data,
736
                                 length);
17✔
737
}
738

739

740
/*
741
 * Create a new Mute Request Object.
742
 */
743
RDMDiscoveryRequest *NewMuteRequest(const UID &source,
11✔
744
                                    const UID &destination,
745
                                    uint8_t transaction_number,
746
                                    uint8_t port_id) {
747
  return new RDMDiscoveryRequest(source,
11✔
748
                                 destination,
749
                                 transaction_number,
750
                                 port_id,
751
                                 ROOT_RDM_DEVICE,
752
                                 PID_DISC_MUTE,
753
                                 NULL,
754
                                 0);
11✔
755
}
756

757

758
/**
759
 * Create a new UnMute request object.
760
 */
761
RDMDiscoveryRequest *NewUnMuteRequest(const UID &source,
7✔
762
                                      const UID &destination,
763
                                      uint8_t transaction_number,
764
                                      uint8_t port_id) {
765
    return new RDMDiscoveryRequest(source,
7✔
766
                                   destination,
767
                                   transaction_number,
768
                                   port_id,
769
                                   ROOT_RDM_DEVICE,
770
                                   PID_DISC_UN_MUTE,
771
                                   NULL,
772
                                   0);
7✔
773
}
774

775

776
/**
777
 * Inflate a discovery response.
778
 */
779
RDMDiscoveryResponse* RDMDiscoveryResponse::InflateFromData(
1✔
780
    const uint8_t *data,
781
    unsigned int length) {
782
  RDMCommandHeader command_message;
1✔
783
  RDMStatusCode code = VerifyData(data, length, &command_message);
1✔
784
  if (code != RDM_COMPLETED_OK) {
1✔
785
    return NULL;
786
  }
787

788
  uint16_t sub_device = JoinUInt8(command_message.sub_device[0],
1✔
789
                                  command_message.sub_device[1]);
1✔
790
  uint16_t param_id = JoinUInt8(command_message.param_id[0],
1✔
791
                                command_message.param_id[1]);
1✔
792

793
  RDMCommandClass command_class = ConvertCommandClass(
2✔
794
      command_message.command_class);
1✔
795

796
  if (command_class == DISCOVER_COMMAND_RESPONSE) {
1✔
797
    return new RDMDiscoveryResponse(
1✔
798
        UID(command_message.source_uid),
1✔
799
        UID(command_message.destination_uid),
2✔
800
        command_message.transaction_number,  // transaction #
1✔
801
        command_message.port_id,  // port id
1✔
802
        command_message.message_count,  // message count
1✔
803
        sub_device,
804
        param_id,
805
        data + sizeof(RDMCommandHeader),
806
        command_message.param_data_length);  // data length
2✔
807
  } else {
808
    OLA_WARN << "Expected a RDM discovery response but got " << command_class;
×
809
    return NULL;
×
810
  }
811
}
812
/**@}*/
813
}  // namespace rdm
814
}  // namespace ola
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