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

OpenLightingProject / ola / 20179851591

12 Dec 2025 09:05PM UTC coverage: 45.048% (-0.7%) from 45.72%
20179851591

Pull #2027

github

web-flow
Bump actions/upload-artifact from 4 to 6

Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 6.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v4...v6)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Pull Request #2027: Bump actions/upload-artifact from 4 to 6

8554 of 19812 branches covered (43.18%)

22094 of 49046 relevant lines covered (45.05%)

50.63 hits per line

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

28.08
/common/rdm/ResponderHelper.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
 * ResponderHelper.cpp
17
 * Copyright (C) 2013 Simon Newton
18
 */
19

20
#define __STDC_LIMIT_MACROS  // for UINT8_MAX & friends
21
#include <stdint.h>
22

23
#include <algorithm>
24
#include <string>
25
#include <vector>
26
#include "ola/Clock.h"
27
#include "ola/Constants.h"
28
#include "ola/Logging.h"
29
#include "ola/base/Array.h"
30
#include "ola/base/Macro.h"
31
#include "ola/network/IPV4Address.h"
32
#include "ola/network/Interface.h"
33
#include "ola/network/InterfacePicker.h"
34
#include "ola/network/MACAddress.h"
35
#include "ola/network/NetworkUtils.h"
36
#include "ola/rdm/RDMEnums.h"
37
#include "ola/rdm/ResponderHelper.h"
38
#include "ola/rdm/ResponderSensor.h"
39
#include "ola/strings/Utils.h"
40

41
namespace ola {
42
namespace rdm {
43

44
using ola::network::HostToNetwork;
45
using ola::network::Interface;
46
using ola::network::InterfacePicker;
47
using ola::network::IPV4Address;
48
using ola::network::MACAddress;
49
using ola::network::NetworkToHost;
50
using ola::strings::StrNLength;
51
using std::min;
52
using std::string;
53
using std::vector;
54

55
template<typename T>
56
static bool GenericExtractValue(const RDMRequest *request, T *output) {
7✔
57
  T value;
58
  if (request->ParamDataSize() != sizeof(value)) {
7!
59
    return false;
60
  }
61

62
  memcpy(reinterpret_cast<uint8_t*>(&value), request->ParamData(),
7✔
63
         sizeof(value));
64
  *output = NetworkToHost(value);
7✔
65
  return true;
7✔
66
}
67

68
bool ResponderHelper::ExtractUInt8(const RDMRequest *request,
7✔
69
                                   uint8_t *output) {
70
  return GenericExtractValue(request, output);
7✔
71
}
72

73
bool ResponderHelper::ExtractUInt16(const RDMRequest *request,
7✔
74
                                    uint16_t *output) {
75
  return GenericExtractValue(request, output);
7✔
76
}
77

78
bool ResponderHelper::ExtractUInt32(const RDMRequest *request,
×
79
                                    uint32_t *output) {
80
  return GenericExtractValue(request, output);
×
81
}
82

83
bool ResponderHelper::ExtractString(const RDMRequest *request,
6✔
84
                                    std::string *output,
85
                                    uint8_t max_length) {
86
  if (request->ParamDataSize() > max_length) {
6✔
87
    return false;
88
  }
89

90
  size_t len = (size_t) request->ParamDataSize();
5✔
91
  if (request->ParamData() != NULL) {
5✔
92
    // StrNLength ensures we stop on the first null we hit
93
    len = StrNLength(reinterpret_cast<const char*>(request->ParamData()),
4✔
94
                     min(len, (size_t) max_length));
4✔
95
  }
96
  const string value(reinterpret_cast<const char*>(request->ParamData()), len);
5✔
97
  *output = value;
5✔
98
  return true;
5✔
99
}
5✔
100

101

102
RDMResponse *ResponderHelper::GetDeviceInfo(
2✔
103
    const RDMRequest *request,
104
    uint16_t device_model,
105
    rdm_product_category product_category,
106
    uint32_t software_version,
107
    uint16_t dmx_footprint,
108
    uint8_t current_personality,
109
    uint8_t personality_count,
110
    uint16_t dmx_start_address,
111
    uint16_t sub_device_count,
112
    uint8_t sensor_count,
113
    uint8_t queued_message_count) {
114
  if (request->ParamDataSize()) {
2✔
115
    return NackWithReason(request, NR_FORMAT_ERROR, queued_message_count);
1✔
116
  }
117

118
  PACK(
1✔
119
  struct device_info_s {
120
    uint16_t rdm_version;
121
    uint16_t model;
122
    uint16_t product_category;
123
    uint32_t software_version;
124
    uint16_t dmx_footprint;
125
    uint8_t current_personality;
126
    uint8_t personality_count;
127
    uint16_t dmx_start_address;
128
    uint16_t sub_device_count;
129
    uint8_t sensor_count;
130
  });
131
  STATIC_ASSERT(sizeof(device_info_s) == 19);
1✔
132

133
  struct device_info_s device_info;
1✔
134
  device_info.rdm_version = HostToNetwork(
1✔
135
      static_cast<uint16_t>(RDM_VERSION_1_0));
136
  device_info.model = HostToNetwork(device_model);
1✔
137
  device_info.product_category = HostToNetwork(
1✔
138
      static_cast<uint16_t>(product_category));
139
  device_info.software_version = HostToNetwork(software_version);
1✔
140
  device_info.dmx_footprint = HostToNetwork(dmx_footprint);
1✔
141
  device_info.current_personality = current_personality;
1✔
142
  device_info.personality_count = personality_count;
1✔
143
  device_info.dmx_start_address = HostToNetwork(dmx_start_address);
1✔
144
  device_info.sub_device_count = HostToNetwork(sub_device_count);
1✔
145
  device_info.sensor_count = sensor_count;
1✔
146
  return GetResponseFromData(
1✔
147
      request,
148
      reinterpret_cast<uint8_t*>(&device_info),
149
      sizeof(device_info),
150
      RDM_ACK,
151
      queued_message_count);
152
}
153

154
RDMResponse *ResponderHelper::GetDeviceInfo(
2✔
155
    const RDMRequest *request,
156
    uint16_t device_model,
157
    rdm_product_category product_category,
158
    uint32_t software_version,
159
    const PersonalityManager *personality_manager,
160
    uint16_t start_address,
161
    uint16_t sub_device_count,
162
    uint8_t sensor_count,
163
    uint8_t queued_message_count) {
164
  return ResponderHelper::GetDeviceInfo(
4✔
165
      request, device_model, product_category, software_version,
166
      personality_manager->ActivePersonalityFootprint(),
2✔
167
      personality_manager->ActivePersonalityNumber(),
2✔
168
      personality_manager->PersonalityCount(),
2✔
169
      (personality_manager->ActivePersonalityFootprint() ?
2✔
170
        start_address : ZERO_FOOTPRINT_DMX_ADDRESS),
171
      sub_device_count, sensor_count, queued_message_count);
2✔
172
}
173

174
RDMResponse *ResponderHelper::GetProductDetailList(
×
175
    const RDMRequest *request,
176
    const vector<rdm_product_detail> &product_details,
177
    uint8_t queued_message_count) {
178
  if (request->ParamDataSize()) {
×
179
    return NackWithReason(request, NR_FORMAT_ERROR, queued_message_count);
×
180
  }
181

182
  uint16_t product_details_raw[product_details.size()];
×
183

184
  for (unsigned int i = 0; i < product_details.size(); i++) {
×
185
    product_details_raw[i] =
×
186
      HostToNetwork(static_cast<uint16_t>(product_details[i]));
×
187
  }
188

189
  return GetResponseFromData(
×
190
      request,
191
      reinterpret_cast<uint8_t*>(&product_details_raw),
192
      sizeof(product_details_raw),
193
      RDM_ACK,
194
      queued_message_count);
195
}
×
196

197
RDMResponse *ResponderHelper::GetPersonality(
×
198
    const RDMRequest *request,
199
    const PersonalityManager *personality_manager,
200
    uint8_t queued_message_count) {
201
  if (request->ParamDataSize()) {
×
202
    return NackWithReason(request, NR_FORMAT_ERROR, queued_message_count);
×
203
  }
204

205
  PACK(
×
206
  struct personality_info_s {
207
    uint8_t personality;
208
    uint8_t total;
209
  });
210
  STATIC_ASSERT(sizeof(personality_info_s) == 2);
×
211

212
  struct personality_info_s personality_info = {
×
213
      personality_manager->ActivePersonalityNumber(),
×
214
      personality_manager->PersonalityCount()
×
215
  };
×
216
  return GetResponseFromData(
×
217
    request,
218
    reinterpret_cast<const uint8_t*>(&personality_info),
219
    sizeof(personality_info),
220
    RDM_ACK,
221
    queued_message_count);
222
}
223

224
RDMResponse *ResponderHelper::SetPersonality(
×
225
    const RDMRequest *request,
226
    PersonalityManager *personality_manager,
227
    uint16_t start_address,
228
    uint8_t queued_message_count) {
229
  uint8_t personality_number;
×
230
  if (!ExtractUInt8(request, &personality_number)) {
×
231
    return NackWithReason(request, NR_FORMAT_ERROR, queued_message_count);
×
232
  }
233

234
  const Personality *personality = personality_manager->Lookup(
×
235
    personality_number);
236

237
  if (!personality) {
×
238
    return NackWithReason(request, NR_DATA_OUT_OF_RANGE, queued_message_count);
×
239
  } else if (start_address + personality->Footprint() - 1 > DMX_UNIVERSE_SIZE) {
×
240
    return NackWithReason(request, NR_DATA_OUT_OF_RANGE, queued_message_count);
×
241
  } else {
242
    personality_manager->SetActivePersonality(personality_number);
×
243
    return EmptySetResponse(request, queued_message_count);
×
244
  }
245
}
246

247
RDMResponse *ResponderHelper::GetPersonalityDescription(
×
248
    const RDMRequest *request,
249
    const PersonalityManager *personality_manager,
250
    uint8_t queued_message_count) {
251
  uint8_t personality_number;
×
252
  if (!ExtractUInt8(request, &personality_number)) {
×
253
    return NackWithReason(request, NR_FORMAT_ERROR, queued_message_count);
×
254
  }
255
  const Personality *personality = personality_manager->Lookup(
×
256
    personality_number);
257

258
  if (!personality) {
×
259
    return NackWithReason(request, NR_DATA_OUT_OF_RANGE, queued_message_count);
×
260
  } else {
261
    PACK(
×
262
    struct personality_description_s {
263
      uint8_t personality;
264
      uint16_t slots_required;
265
      char description[MAX_RDM_STRING_LENGTH];
266
    });
267
    STATIC_ASSERT(sizeof(personality_description_s) == 35);
×
268

269
    struct personality_description_s personality_description;
×
270
    personality_description.personality = personality_number;
×
271
    personality_description.slots_required =
×
272
        HostToNetwork(personality->Footprint());
×
273

274
    size_t str_len = min(personality->Description().size(),
×
275
                         sizeof(personality_description.description));
×
276
    strncpy(personality_description.description,
×
277
            personality->Description().c_str(), str_len);
×
278

279
    unsigned int param_data_size = (
×
280
        sizeof(personality_description) -
281
        sizeof(personality_description.description) + str_len);
×
282

283
    return GetResponseFromData(
×
284
        request,
285
        reinterpret_cast<uint8_t*>(&personality_description),
286
        param_data_size,
287
        RDM_ACK,
288
        queued_message_count);
289
  }
290
}
291

292

293
/**
294
 * Get slot info
295
 */
296
RDMResponse *ResponderHelper::GetSlotInfo(
2✔
297
    const RDMRequest *request,
298
    const PersonalityManager *personality_manager,
299
    uint8_t queued_message_count) {
300
  if (request->ParamDataSize()) {
2✔
301
    return NackWithReason(request, NR_FORMAT_ERROR, queued_message_count);
1✔
302
  }
303
  const SlotDataCollection *slot_data =
1✔
304
      personality_manager->ActivePersonality()->GetSlotData();
1✔
305

306
  if (slot_data->SlotCount() == 0) {
1✔
307
    return EmptyGetResponse(request, queued_message_count);
×
308
  }
309

310
  PACK(
1✔
311
  struct slot_info_s {
312
    uint16_t offset;
313
    uint8_t type;
314
    uint16_t label;
315
  });
316
  STATIC_ASSERT(sizeof(slot_info_s) == 5);
1✔
317

318
  slot_info_s slot_info_raw[slot_data->SlotCount()];
1✔
319

320
  for (uint16_t slot = 0; slot < slot_data->SlotCount(); slot++) {
6✔
321
    const SlotData *sd = slot_data->Lookup(slot);
5✔
322
    slot_info_raw[slot].offset = HostToNetwork(slot);
5✔
323
    slot_info_raw[slot].type = static_cast<uint8_t>(sd->SlotType());
5✔
324
    slot_info_raw[slot].label = HostToNetwork(sd->SlotIDDefinition());
5✔
325
  }
326

327
  return GetResponseFromData(
1✔
328
      request,
329
      reinterpret_cast<uint8_t*>(&slot_info_raw),
330
      sizeof(slot_info_raw),
331
      RDM_ACK,
332
      queued_message_count);
333
}
2✔
334

335

336
/**
337
 * Get a slot description
338
 */
339
RDMResponse *ResponderHelper::GetSlotDescription(
×
340
    const RDMRequest *request,
341
    const PersonalityManager *personality_manager,
342
    uint8_t queued_message_count) {
343
  uint16_t slot_number;
×
344
  if (!ExtractUInt16(request, &slot_number)) {
×
345
    return NackWithReason(request, NR_FORMAT_ERROR, queued_message_count);
×
346
  }
347

348
  const SlotData *slot_data =
×
349
      personality_manager->ActivePersonality()->GetSlotData(slot_number);
×
350

351
  if (!slot_data) {
×
352
    return NackWithReason(request, NR_DATA_OUT_OF_RANGE, queued_message_count);
×
353
  }
354

355
  if (!slot_data->HasDescription()) {
×
356
    return NackWithReason(request, NR_DATA_OUT_OF_RANGE, queued_message_count);
×
357
  }
358

359
  PACK(
×
360
  struct slot_description_s {
361
    uint16_t slot;
362
    char description[MAX_RDM_STRING_LENGTH];
363
  });
364
  STATIC_ASSERT(sizeof(slot_description_s) == 34);
×
365

366
  struct slot_description_s slot_description;
×
367
  slot_description.slot = HostToNetwork(slot_number);
×
368

369
  size_t str_len = min(slot_data->Description().size(),
×
370
                       sizeof(slot_description.description));
×
371
  strncpy(slot_description.description, slot_data->Description().c_str(),
×
372
          str_len);
373

374
  unsigned int param_data_size = (
×
375
      sizeof(slot_description) -
376
      sizeof(slot_description.description) + str_len);
×
377

378
  return GetResponseFromData(request,
×
379
                             reinterpret_cast<uint8_t*>(&slot_description),
380
                             param_data_size,
381
                             RDM_ACK,
382
                             queued_message_count);
383
}
384

385

386
/**
387
 * Get slot default values
388
 */
389
RDMResponse *ResponderHelper::GetSlotDefaultValues(
×
390
    const RDMRequest *request,
391
    const PersonalityManager *personality_manager,
392
    uint8_t queued_message_count) {
393
  if (request->ParamDataSize()) {
×
394
    return NackWithReason(request, NR_FORMAT_ERROR, queued_message_count);
×
395
  }
396
  const SlotDataCollection *slot_data =
×
397
      personality_manager->ActivePersonality()->GetSlotData();
×
398

399
  if (slot_data->SlotCount() == 0) {
×
400
    return EmptyGetResponse(request, queued_message_count);
×
401
  }
402

403
  PACK(
×
404
  struct slot_default_s {
405
    uint16_t offset;
406
    uint8_t value;
407
  });
408
  STATIC_ASSERT(sizeof(slot_default_s) == 3);
×
409

410
  slot_default_s slot_default_raw[slot_data->SlotCount()];
×
411

412
  for (uint16_t slot = 0; slot < slot_data->SlotCount(); slot++) {
×
413
    const SlotData *sd = slot_data->Lookup(slot);
×
414
    slot_default_raw[slot].offset = HostToNetwork(slot);
×
415
    slot_default_raw[slot].value =
×
416
        static_cast<uint8_t>(sd->DefaultSlotValue());
×
417
  }
418

419
  return GetResponseFromData(
×
420
      request,
421
      reinterpret_cast<uint8_t*>(&slot_default_raw),
422
      sizeof(slot_default_raw),
423
      RDM_ACK,
424
      queued_message_count);
425
}
×
426

427

428
/**
429
 * Get the start address
430
 */
431
RDMResponse *ResponderHelper::GetDmxAddress(
4✔
432
    const RDMRequest *request,
433
    const PersonalityManager *personality_manager,
434
    uint16_t start_address,
435
    uint8_t queued_message_count) {
436
  return ResponderHelper::GetUInt16Value(
8✔
437
    request,
438
    ((personality_manager->ActivePersonalityFootprint() == 0) ?
4✔
439
        ZERO_FOOTPRINT_DMX_ADDRESS : start_address),
440
    queued_message_count);
4✔
441
}
442

443
/**
444
 * Set the start address
445
 */
446
RDMResponse *ResponderHelper::SetDmxAddress(
4✔
447
    const RDMRequest *request,
448
    const PersonalityManager *personality_manager,
449
    uint16_t *dmx_address,
450
    uint8_t queued_message_count) {
451
  uint16_t address;
4✔
452
  if (!ResponderHelper::ExtractUInt16(request, &address)) {
4✔
453
    return NackWithReason(request, NR_FORMAT_ERROR);
×
454
  }
455

456
  uint16_t end_address = (1 + DMX_UNIVERSE_SIZE -
4✔
457
                          personality_manager->ActivePersonalityFootprint());
4✔
458
  if (address == 0 || address > end_address) {
4✔
459
    return NackWithReason(request, NR_DATA_OUT_OF_RANGE, queued_message_count);
×
460
  } else if (personality_manager->ActivePersonalityFootprint() == 0) {
4✔
461
    return NackWithReason(request, NR_DATA_OUT_OF_RANGE, queued_message_count);
×
462
  } else {
463
    *dmx_address = address;
4✔
464
    return EmptySetResponse(request, queued_message_count);
4✔
465
  }
466
}
467

468
/**
469
 * Get a sensor definition
470
 */
471
RDMResponse *ResponderHelper::GetSensorDefinition(
×
472
    const RDMRequest *request, const Sensors &sensor_list) {
473
  uint8_t sensor_number;
×
474
  if (!ResponderHelper::ExtractUInt8(request, &sensor_number)) {
×
475
    return NackWithReason(request, NR_FORMAT_ERROR);
×
476
  }
477

478
  if (sensor_number >= sensor_list.size()) {
×
479
    return NackWithReason(request, NR_DATA_OUT_OF_RANGE);
×
480
  }
481

482
  PACK(
×
483
  struct sensor_definition_s {
484
    uint8_t sensor;
485
    uint8_t type;
486
    uint8_t unit;
487
    uint8_t prefix;
488
    int16_t range_min;
489
    int16_t range_max;
490
    int16_t normal_min;
491
    int16_t normal_max;
492
    uint8_t recorded_support;
493
    char description[MAX_RDM_STRING_LENGTH];
494
  });
495
  STATIC_ASSERT(sizeof(sensor_definition_s) == 45);
×
496

497
  const Sensor *sensor = sensor_list.at(sensor_number);
×
498
  struct sensor_definition_s sensor_definition;
×
499
  sensor_definition.sensor = sensor_number;
×
500
  sensor_definition.type = sensor->Type();
×
501
  sensor_definition.unit = sensor->Unit();
×
502
  sensor_definition.prefix = sensor->Prefix();
×
503
  sensor_definition.range_min = HostToNetwork(sensor->RangeMin());
×
504
  sensor_definition.range_max = HostToNetwork(sensor->RangeMax());
×
505
  sensor_definition.normal_min = HostToNetwork(sensor->NormalMin());
×
506
  sensor_definition.normal_max = HostToNetwork(sensor->NormalMax());
×
507
  sensor_definition.recorded_support = sensor->RecordedSupportBitMask();
×
508
  strings::CopyToFixedLengthBuffer(sensor->Description(),
×
509
                                   sensor_definition.description,
510
                                   arraysize(sensor_definition.description));
511
  return GetResponseFromData(
×
512
    request,
513
    reinterpret_cast<const uint8_t*>(&sensor_definition),
514
    sizeof(sensor_definition));
515
}
516

517
/**
518
 * Get a sensor value
519
 */
520
RDMResponse *ResponderHelper::GetSensorValue(
×
521
    const RDMRequest *request, const Sensors &sensor_list) {
522
  uint8_t sensor_number;
×
523
  if (!ResponderHelper::ExtractUInt8(request, &sensor_number)) {
×
524
    return NackWithReason(request, NR_FORMAT_ERROR);
×
525
  }
526

527
  if (sensor_number >= sensor_list.size()) {
×
528
    return NackWithReason(request, NR_DATA_OUT_OF_RANGE);
×
529
  }
530

531
  Sensor *sensor = sensor_list.at(sensor_number);
×
532
  struct sensor_value_s sensor_value = {
×
533
    sensor_number,
534
    HostToNetwork(sensor->FetchValue()),
×
535
    HostToNetwork(sensor->Lowest()),
×
536
    HostToNetwork(sensor->Highest()),
×
537
    HostToNetwork(sensor->Recorded()),
×
538
  };
×
539

540
  return GetResponseFromData(
×
541
    request,
542
    reinterpret_cast<const uint8_t*>(&sensor_value),
543
    sizeof(sensor_value));
544
}
545

546
/**
547
 * Set a sensor value
548
 */
549
RDMResponse *ResponderHelper::SetSensorValue(
×
550
    const RDMRequest *request, const Sensors &sensor_list) {
551
  uint8_t sensor_number;
×
552
  if (!ResponderHelper::ExtractUInt8(request, &sensor_number)) {
×
553
    return NackWithReason(request, NR_FORMAT_ERROR);
×
554
  }
555

556
  int16_t value = 0;
×
557
  if (sensor_number == ALL_SENSORS) {
×
558
    Sensors::const_iterator iter = sensor_list.begin();
×
559
    for (; iter != sensor_list.end(); ++iter) {
×
560
      value = (*iter)->Reset();
×
561
    }
562
  } else if (sensor_number < sensor_list.size()) {
×
563
    Sensor *sensor = sensor_list.at(sensor_number);
×
564
    value = sensor->Reset();
×
565
  } else {
566
    return NackWithReason(request, NR_DATA_OUT_OF_RANGE);
×
567
  }
568

569
  struct sensor_value_s sensor_value = {
×
570
    sensor_number,
571
    HostToNetwork(value),
×
572
    HostToNetwork(value),
×
573
    HostToNetwork(value),
×
574
    HostToNetwork(value),
×
575
  };
×
576

577
  return GetResponseFromData(
×
578
    request,
579
    reinterpret_cast<const uint8_t*>(&sensor_value),
580
    sizeof(sensor_value));
581
}
582

583

584
/**
585
 * Record a sensor
586
 */
587
RDMResponse *ResponderHelper::RecordSensor(
×
588
    const RDMRequest *request, const Sensors &sensor_list) {
589
  uint8_t sensor_number;
×
590
  if (!ResponderHelper::ExtractUInt8(request, &sensor_number)) {
×
591
    return NackWithReason(request, NR_FORMAT_ERROR);
×
592
  }
593

594
  if ((sensor_number == ALL_SENSORS) && (sensor_list.size() > 0)) {
×
595
    Sensors::const_iterator iter = sensor_list.begin();
596
    for (; iter != sensor_list.end(); ++iter) {
×
597
      (*iter)->Record();
×
598
    }
599
  } else if (sensor_number < sensor_list.size()) {
×
600
    Sensor *sensor = sensor_list.at(sensor_number);
×
601
    sensor->Record();
×
602
  } else {
603
    return NackWithReason(request, NR_DATA_OUT_OF_RANGE);
×
604
  }
605

606
  return GetResponseFromData(request, NULL, 0);
×
607
}
608

609
/**
610
 * Get the clock response.
611
 */
612
RDMResponse *ResponderHelper::GetRealTimeClock(
×
613
    const RDMRequest *request,
614
    uint8_t queued_message_count) {
615
  if (request->ParamDataSize()) {
×
616
    return NackWithReason(request, NR_FORMAT_ERROR, queued_message_count);
×
617
  }
618

619
  PACK(
×
620
  struct clock_s {
621
    uint16_t year;
622
    uint8_t month;
623
    uint8_t day;
624
    uint8_t hour;
625
    uint8_t minute;
626
    uint8_t second;
627
  });
628
  STATIC_ASSERT(sizeof(clock_s) == 7);
×
629

630
  time_t now;
×
631
  now = time(NULL);
×
632
  struct tm tm_now;
×
633
#ifdef _WIN32
634
  tm_now = *localtime(&now);  // NOLINT(runtime/threadsafe_fn)
635
#else
636
  localtime_r(&now, &tm_now);
×
637
#endif  // _WIN32
638

639
  struct clock_s clock;
×
640
  clock.year = HostToNetwork(static_cast<uint16_t>(1900 + tm_now.tm_year));
×
641
  clock.month = tm_now.tm_mon + 1;
×
642
  clock.day = tm_now.tm_mday;
×
643
  clock.hour = tm_now.tm_hour;
×
644
  clock.minute = tm_now.tm_min;
×
645
  clock.second = tm_now.tm_sec;
×
646

647
  return GetResponseFromData(
×
648
      request,
649
      reinterpret_cast<uint8_t*>(&clock),
650
      sizeof(clock),
651
      RDM_ACK,
652
      queued_message_count);
653
}
654

655
RDMResponse *ResponderHelper::GetListInterfaces(
2✔
656
    const RDMRequest *request,
657
    const NetworkManagerInterface *network_manager,
658
    uint8_t queued_message_count) {
659
  if (request->ParamDataSize()) {
2✔
660
    return NackWithReason(request, NR_FORMAT_ERROR, queued_message_count);
1✔
661
  }
662

663
  vector<Interface> interfaces =
1✔
664
      network_manager->GetInterfacePicker()->GetInterfaces(false);
1✔
665

666
  if (interfaces.size() == 0) {
1✔
667
    return EmptyGetResponse(request, queued_message_count);
×
668
  }
669

670
  std::sort(interfaces.begin(), interfaces.end(),
1✔
671
            ola::network::InterfaceIndexOrdering());
672

673
  uint16_t interface_count = std::count_if(
1✔
674
      interfaces.begin(), interfaces.end(), IsInterfaceIndexValidInterface);
1✔
675

676
  PACK(
1✔
677
  struct list_interfaces_s {
678
    uint32_t index;
679
    uint16_t type;
680
  });
681
  STATIC_ASSERT(sizeof(list_interfaces_s) == 6);
1✔
682

683
  list_interfaces_s list_interfaces[interface_count];
1✔
684

685
  // Reorder so valid interfaces are first
686
  std::stable_partition(interfaces.begin(), interfaces.end(),
1✔
687
                        IsInterfaceIndexValidInterface);
688

689
  // Then just iterate through the valid ones
690
  vector<Interface>::iterator iter = interfaces.begin();
1✔
691
  for (uint16_t i = 0; i < interface_count; i++) {
3✔
692
    list_interfaces[i].index = HostToNetwork(iter[i].index);
2✔
693
    list_interfaces[i].type = HostToNetwork(
2✔
694
        static_cast<uint16_t>(iter[i].type));
2✔
695
  }
696

697
  return GetResponseFromData(
1✔
698
      request,
699
      reinterpret_cast<uint8_t*>(&list_interfaces),
700
      sizeof(list_interfaces),
701
      RDM_ACK,
702
      queued_message_count);
703
}
3✔
704

705

706
RDMResponse *ResponderHelper::GetInterfaceLabel(
×
707
    const RDMRequest *request,
708
    const NetworkManagerInterface *network_manager,
709
    uint8_t queued_message_count) {
710
  uint32_t index;
×
711
  if (!ResponderHelper::ExtractUInt32(request, &index)) {
×
712
    return NackWithReason(request, NR_FORMAT_ERROR);
×
713
  }
714

715
  Interface interface;
×
716
  if (!FindInterface(network_manager, &interface, index)) {
×
717
    return NackWithReason(request, NR_DATA_OUT_OF_RANGE);
×
718
  }
719

720
  PACK(
×
721
  struct interface_label_s {
722
    uint32_t index;
723
    char label[MAX_RDM_STRING_LENGTH];
724
  });
725
  STATIC_ASSERT(sizeof(interface_label_s) == 36);
×
726

727
  struct interface_label_s interface_label;
×
728
  interface_label.index = HostToNetwork(interface.index);
×
729

730
  size_t str_len = min(interface.name.size(), sizeof(interface_label.label));
×
731
  strncpy(interface_label.label, interface.name.c_str(), str_len);
×
732

733
  unsigned int param_data_size = (
×
734
      sizeof(interface_label) -
735
      sizeof(interface_label.label) + str_len);
×
736

737
  return GetResponseFromData(request,
×
738
                             reinterpret_cast<uint8_t*>(&interface_label),
739
                             param_data_size,
740
                             RDM_ACK,
741
                             queued_message_count);
742
}
×
743

744
RDMResponse *ResponderHelper::GetInterfaceHardwareAddressType1(
×
745
    const RDMRequest *request,
746
    const NetworkManagerInterface *network_manager,
747
    uint8_t queued_message_count) {
748
  uint32_t index;
×
749
  if (!ResponderHelper::ExtractUInt32(request, &index)) {
×
750
    return NackWithReason(request, NR_FORMAT_ERROR);
×
751
  }
752

753
  Interface interface;
×
754
  if (!FindInterface(network_manager, &interface, index)) {
×
755
    return NackWithReason(request, NR_DATA_OUT_OF_RANGE);
×
756
  }
757

758
  // Only return type 1 (Ethernet)
759
  if (interface.type != Interface::ARP_ETHERNET_TYPE) {
×
760
    return NackWithReason(request, NR_DATA_OUT_OF_RANGE);
×
761
  }
762

763
  PACK(
×
764
  struct interface_hardware_address_s {
765
    uint32_t index;
766
    uint8_t hardware_address[MACAddress::LENGTH];
767
  });
768
  STATIC_ASSERT(sizeof(interface_hardware_address_s) == 10);
×
769

770
  struct interface_hardware_address_s interface_hardware_address;
×
771
  interface_hardware_address.index = HostToNetwork(interface.index);
×
772
  interface.hw_address.Get(interface_hardware_address.hardware_address);
×
773

774
  return GetResponseFromData(
×
775
      request,
776
      reinterpret_cast<uint8_t*>(&interface_hardware_address),
777
      sizeof(interface_hardware_address),
778
      RDM_ACK,
779
      queued_message_count);
780
}
×
781

782
RDMResponse *ResponderHelper::GetIPV4CurrentAddress(
×
783
    const RDMRequest *request,
784
    const NetworkManagerInterface *network_manager,
785
    uint8_t queued_message_count) {
786
  uint32_t index;
×
787
  if (!ResponderHelper::ExtractUInt32(request, &index)) {
×
788
    return NackWithReason(request, NR_FORMAT_ERROR);
×
789
  }
790

791
  Interface interface;
×
792
  if (!FindInterface(network_manager, &interface, index)) {
×
793
    return NackWithReason(request, NR_DATA_OUT_OF_RANGE);
×
794
  }
795

796
  PACK(
×
797
  struct ipv4_current_address_s {
798
    uint32_t index;
799
    uint32_t ipv4_address;
800
    uint8_t netmask;
801
    uint8_t dhcp;
802
  });
803
  STATIC_ASSERT(sizeof(ipv4_current_address_s) == 10);
×
804

805
  struct ipv4_current_address_s ipv4_current_address;
×
806
  ipv4_current_address.index = HostToNetwork(interface.index);
×
807

808
  // Already in correct byte order
809
  ipv4_current_address.ipv4_address = interface.ip_address.AsInt();
×
810

811
  uint8_t mask = UINT8_MAX;
×
812
  if (!IPV4Address::ToCIDRMask(interface.subnet_mask, &mask)) {
×
813
    OLA_WARN << "Error converting " << interface.subnet_mask
×
814
             << " to CIDR value";
×
815
  }
816

817
  ipv4_current_address.netmask = mask;
×
818
  ipv4_current_address.dhcp = static_cast<uint8_t>(
×
819
      network_manager->GetDHCPStatus(interface));
×
820

821
  return GetResponseFromData(
×
822
      request,
823
      reinterpret_cast<uint8_t*>(&ipv4_current_address),
824
      sizeof(ipv4_current_address),
825
      RDM_ACK,
826
      queued_message_count);
827
}
×
828

829

830
RDMResponse *ResponderHelper::GetIPV4DefaultRoute(
×
831
    const RDMRequest *request,
832
    const NetworkManagerInterface *network_manager,
833
    uint8_t queued_message_count) {
834
  if (request->ParamDataSize()) {
×
835
    return NackWithReason(request, NR_FORMAT_ERROR, queued_message_count);
×
836
  }
837

838
  int32_t if_index = Interface::DEFAULT_INDEX;
×
839
  IPV4Address default_route;
×
840
  if (!network_manager->GetIPV4DefaultRoute(&if_index, &default_route)) {
×
841
    return NackWithReason(request, NR_HARDWARE_FAULT);
×
842
  }
843

844
  PACK(
×
845
  struct ipv4_default_route_s {
846
    uint32_t if_index;
847
    uint32_t default_route;
848
  });
849
  STATIC_ASSERT(sizeof(ipv4_default_route_s) == 8);
×
850

851
  struct ipv4_default_route_s ipv4_default_route;
×
852

853
  if (if_index == Interface::DEFAULT_INDEX) {
×
854
    // No default route interface index set, return special value
855
    ipv4_default_route.if_index = HostToNetwork(NO_DEFAULT_ROUTE);
×
856
  } else {
857
    ipv4_default_route.if_index = HostToNetwork(if_index);
×
858
  }
859

860
  if (default_route.IsWildcard()) {
×
861
    // No default route set, return special value
862
    ipv4_default_route.default_route = HostToNetwork(NO_DEFAULT_ROUTE);
×
863
  } else {
864
    // Already in correct byte order
865
    ipv4_default_route.default_route = default_route.AsInt();
×
866
  }
867

868
  return GetResponseFromData(
×
869
      request,
870
      reinterpret_cast<uint8_t*>(&ipv4_default_route),
871
      sizeof(ipv4_default_route),
872
      RDM_ACK,
873
      queued_message_count);
874
}
875

876

877
RDMResponse *ResponderHelper::GetDNSHostname(
×
878
    const RDMRequest *request,
879
    const NetworkManagerInterface *network_manager,
880
    uint8_t queued_message_count) {
881
  if (request->ParamDataSize()) {
×
882
    return NackWithReason(request, NR_FORMAT_ERROR, queued_message_count);
×
883
  }
884

885
  const string hostname = network_manager->GetHostname();
×
886
  if (hostname.empty() || hostname.length() > MAX_RDM_HOSTNAME_LENGTH) {
×
887
    // Hostname outside of the allowed parameters for RDM, return an error
888
    return NackWithReason(request, NR_HARDWARE_FAULT);
×
889
  } else {
890
    return GetString(request,
×
891
                     hostname,
892
                     queued_message_count,
893
                     MAX_RDM_HOSTNAME_LENGTH);
894
  }
895
}
×
896

897

898
RDMResponse *ResponderHelper::GetDNSDomainName(
×
899
    const RDMRequest *request,
900
    const NetworkManagerInterface *network_manager,
901
    uint8_t queued_message_count) {
902
  if (request->ParamDataSize()) {
×
903
    return NackWithReason(request, NR_FORMAT_ERROR, queued_message_count);
×
904
  }
905

906
  string domain_name = network_manager->GetDomainName();
×
907
  if (domain_name.length() > MAX_RDM_DOMAIN_NAME_LENGTH) {
×
908
    // Domain name outside of the allowed parameters for RDM, return an error
909
    return NackWithReason(request, NR_HARDWARE_FAULT);
×
910
  } else {
911
    return GetString(request,
×
912
                     domain_name,
913
                     queued_message_count,
914
                     MAX_RDM_DOMAIN_NAME_LENGTH);
915
  }
916
}
×
917

918
RDMResponse *ResponderHelper::GetDNSNameServer(
×
919
    const RDMRequest *request,
920
    const NetworkManagerInterface *network_manager,
921
    uint8_t queued_message_count) {
922
  uint8_t name_server_number;
×
923
  if (!ResponderHelper::ExtractUInt8(request, &name_server_number)) {
×
924
    return NackWithReason(request, NR_FORMAT_ERROR);
×
925
  }
926

927
  vector<IPV4Address> name_servers;
×
928
  if (!network_manager->GetNameServers(&name_servers)) {
×
929
    return NackWithReason(request, NR_HARDWARE_FAULT);
×
930
  }
931

932
  if ((name_server_number >= name_servers.size()) ||
×
933
      (name_server_number > DNS_NAME_SERVER_MAX_INDEX)) {
934
    return NackWithReason(request, NR_DATA_OUT_OF_RANGE);
×
935
  }
936

937
  PACK(
×
938
  struct name_server_s {
939
    uint8_t index;
940
    uint32_t address;
941
  });
942
  STATIC_ASSERT(sizeof(name_server_s) == 5);
×
943

944
  struct name_server_s name_server;
×
945
  name_server.index = name_server_number;
×
946
  // s_addr is already in network byte order, so doesn't need converting
947
  name_server.address = name_servers.at(name_server_number).AsInt();
×
948

949
  return GetResponseFromData(
×
950
    request,
951
    reinterpret_cast<const uint8_t*>(&name_server),
952
    sizeof(name_server),
953
    RDM_ACK,
954
    queued_message_count);
955
}
×
956

957
RDMResponse *ResponderHelper::GetParamDescription(
1✔
958
    const RDMRequest *request,
959
    uint16_t pid,
960
    uint8_t pdl_size,
961
    rdm_data_type data_type,
962
    rdm_command_class command_class,
963
    rdm_pid_unit unit,
964
    rdm_pid_prefix prefix,
965
    uint32_t min_value,
966
    uint32_t default_value,
967
    uint32_t max_value,
968
    string description,
969
    uint8_t queued_message_count) {
970
  PACK(
1✔
971
  struct parameter_description_s {
972
    uint16_t pid;
973
    uint8_t pdl_size;
974
    uint8_t data_type;
975
    uint8_t command_class;
976
    uint8_t type;
977
    uint8_t unit;
978
    uint8_t prefix;
979
    uint32_t min_value;
980
    uint32_t default_value;
981
    uint32_t max_value;
982
    char description[MAX_RDM_STRING_LENGTH];
983
  });
984
  STATIC_ASSERT(sizeof(parameter_description_s) == 52);
1✔
985

986
  struct parameter_description_s param_description;
1✔
987
  param_description.pid = HostToNetwork(pid);
1✔
988
  param_description.pdl_size = HostToNetwork(pdl_size);
1✔
989
  param_description.data_type = HostToNetwork(
1✔
990
      static_cast<uint8_t>(data_type));
991
  param_description.command_class = HostToNetwork(
1✔
992
      static_cast<uint8_t>(command_class));
993
  param_description.type = 0;
1✔
994
  param_description.unit = HostToNetwork(
1✔
995
      static_cast<uint8_t>(unit));
996
  param_description.prefix = HostToNetwork(
1✔
997
      static_cast<uint8_t>(prefix));
998
  param_description.min_value = min_value;
1✔
999
  param_description.default_value = default_value;
1✔
1000
  param_description.max_value = max_value;
1✔
1001

1002
  size_t str_len = min(description.size(),
1✔
1003
                       sizeof(param_description.description));
1✔
1004
  strncpy(param_description.description, description.c_str(), str_len);
1✔
1005

1006
  unsigned int param_data_size = (
1✔
1007
      sizeof(param_description) -
1008
      sizeof(param_description.description) + str_len);
1✔
1009

1010
  return GetResponseFromData(
1✔
1011
      request,
1012
      reinterpret_cast<uint8_t*>(&param_description),
1013
      param_data_size,
1014
      RDM_ACK,
1015
      queued_message_count);
1✔
1016
}
1017

1018
RDMResponse *ResponderHelper::GetASCIIParamDescription(
1✔
1019
        const RDMRequest *request,
1020
        uint16_t pid,
1021
        rdm_command_class command_class,
1022
        string description,
1023
        uint8_t queued_message_count) {
1024
  return GetParamDescription(
1✔
1025
      request,
1026
      pid,
1027
      static_cast<uint8_t>(MAX_RDM_STRING_LENGTH),
1028
      DS_ASCII,
1029
      command_class,
1030
      UNITS_NONE,
1031
      PREFIX_NONE,
1032
      static_cast<uint32_t>(0),
1033
      static_cast<uint32_t>(0),
1034
      static_cast<uint32_t>(0),
1035
      description,
1036
      queued_message_count);
1✔
1037
}
1038

1039
RDMResponse *ResponderHelper::GetBitFieldParamDescription(
×
1040
        const RDMRequest *request,
1041
        uint16_t pid,
1042
        uint8_t pdl_size,
1043
        rdm_command_class command_class,
1044
        string description,
1045
        uint8_t queued_message_count) {
1046
  return GetParamDescription(
×
1047
      request,
1048
      pid,
1049
      pdl_size,
1050
      DS_BIT_FIELD,
1051
      command_class,
1052
      UNITS_NONE,
1053
      PREFIX_NONE,
1054
      static_cast<uint32_t>(0),
1055
      static_cast<uint32_t>(0),
1056
      static_cast<uint32_t>(0),
1057
      description,
1058
      queued_message_count);
×
1059
}
1060

1061
/*
1062
 * Handle a request that returns an IPv4 address
1063
 */
1064
RDMResponse *ResponderHelper::GetIPV4Address(
×
1065
    const RDMRequest *request,
1066
    const IPV4Address &value,
1067
    uint8_t queued_message_count) {
1068
  return GetUInt32Value(request,
×
1069
                        // Flip it back because s_addr is in network byte order
1070
                        // already
1071
                        NetworkToHost(value.AsInt()),
1072
                        queued_message_count);
×
1073
}
1074

1075
RDMResponse *ResponderHelper::GetTestData(
×
1076
    const RDMRequest *request,
1077
    uint8_t queued_message_count) {
1078
  uint16_t pattern_length;
×
1079
  if (!ExtractUInt16(request, &pattern_length)) {
×
1080
    return NackWithReason(request, NR_FORMAT_ERROR, queued_message_count);
×
1081
  }
1082

1083
  if (pattern_length > MAX_RDM_TEST_DATA_PATTERN_LENGTH) {
×
1084
    return NackWithReason(request, NR_DATA_OUT_OF_RANGE, queued_message_count);
×
1085
  }
1086

1087
  uint8_t pattern_data[pattern_length];
×
1088

1089
  for (unsigned int i = 0; i < pattern_length; i++) {
×
1090
    // Need to return values 0-255, 0... etc
1091
    pattern_data[i] = i % (UINT8_MAX + 1);
×
1092
  }
1093

1094
  return GetResponseFromData(
×
1095
      request,
1096
      reinterpret_cast<uint8_t*>(&pattern_data),
1097
      sizeof(pattern_data),
1098
      RDM_ACK,
1099
      queued_message_count);
1100
}
×
1101

1102
RDMResponse *ResponderHelper::SetTestData(
×
1103
    const RDMRequest *request,
1104
    uint8_t queued_message_count) {
1105
  return GetResponseFromData(
×
1106
      request,
1107
      request->ParamData(),
1108
      request->ParamDataSize(),
1109
      RDM_ACK,
1110
      queued_message_count);
×
1111
}
1112

1113
RDMResponse *ResponderHelper::GetListTags(
×
1114
    const RDMRequest *request,
1115
    const TagSet *tag_set,
1116
    uint8_t queued_message_count) {
1117
  if (request->ParamDataSize()) {
×
1118
    return NackWithReason(request, NR_FORMAT_ERROR, queued_message_count);
×
1119
  }
1120

1121
  uint8_t tags[(MAX_RDM_STRING_LENGTH + 1) * tag_set->Size()];
×
1122
  unsigned int pdl = sizeof(tags);
×
1123

1124
  tag_set->Pack(tags, &pdl);
×
1125

1126
  return GetResponseFromData(request, tags, pdl,
×
1127
                             RDM_ACK, queued_message_count);
1128
}
×
1129

1130
RDMResponse *ResponderHelper::SetAddTag(
×
1131
    const RDMRequest *request,
1132
    TagSet *tag_set,
1133
    uint8_t queued_message_count) {
1134
  string tag;
×
1135
  if (!ResponderHelper::ExtractString(request, &tag)) {
×
1136
    return NackWithReason(request, NR_FORMAT_ERROR, queued_message_count);
×
1137
  }
1138

1139
  tag_set->AddTag(tag);
×
1140

1141
  return ResponderHelper::EmptySetResponse(request, queued_message_count);
×
1142
}
×
1143

1144
RDMResponse *ResponderHelper::SetRemoveTag(
×
1145
    const RDMRequest *request,
1146
    TagSet *tag_set,
1147
    uint8_t queued_message_count) {
1148
  string tag;
×
1149
  if (!ResponderHelper::ExtractString(request, &tag)) {
×
1150
    return NackWithReason(request, NR_FORMAT_ERROR, queued_message_count);
×
1151
  }
1152

1153
  if (tag_set->Contains(tag)) {
×
1154
    tag_set->RemoveTag(tag);
×
1155

1156
    return ResponderHelper::EmptySetResponse(request, queued_message_count);
×
1157
  } else {
1158
    return NackWithReason(request, NR_DATA_OUT_OF_RANGE, queued_message_count);
×
1159
  }
1160
}
×
1161

1162
RDMResponse *ResponderHelper::GetCheckTag(
×
1163
    const RDMRequest *request,
1164
    const TagSet *tag_set,
1165
    uint8_t queued_message_count) {
1166
  string tag;
×
1167
  if (!ResponderHelper::ExtractString(request, &tag)) {
×
1168
    return NackWithReason(request, NR_FORMAT_ERROR, queued_message_count);
×
1169
  }
1170

1171
  uint8_t param = tag_set->Contains(tag) ? 1 : 0;
×
1172

1173
  return GetResponseFromData(request, &param, sizeof(param),
×
1174
                             RDM_ACK, queued_message_count);
1175
}
×
1176

1177
RDMResponse *ResponderHelper::SetClearTags(
×
1178
    const RDMRequest *request,
1179
    TagSet *tag_set,
1180
    uint8_t queued_message_count) {
1181
  if (request->ParamDataSize()) {
×
1182
    return NackWithReason(request, NR_FORMAT_ERROR, queued_message_count);
×
1183
  }
1184

1185
  tag_set->Clear();
×
1186

1187
  return ResponderHelper::EmptySetResponse(request, queued_message_count);
×
1188
}
1189

1190
/**
1191
 * @brief Handle a request that returns a string
1192
 * @note this truncates the string to max_length
1193
 */
1194
RDMResponse *ResponderHelper::GetString(
4✔
1195
    const RDMRequest *request,
1196
    const string &value,
1197
    uint8_t queued_message_count,
1198
    uint8_t max_length) {
1199
  if (request->ParamDataSize()) {
4✔
1200
    return NackWithReason(request, NR_FORMAT_ERROR, queued_message_count);
2✔
1201
  }
1202
  string sanitised_value = value.substr(
2✔
1203
      0,
1204
      min(static_cast<uint8_t>(value.length()), max_length));
2✔
1205
  return GetResponseFromData(
2✔
1206
      request,
1207
      reinterpret_cast<const uint8_t*>(sanitised_value.data()),
2✔
1208
      sanitised_value.size(),
2✔
1209
      RDM_ACK,
1210
      queued_message_count);
1211
}
2✔
1212

1213
RDMResponse *ResponderHelper::EmptyGetResponse(
×
1214
    const RDMRequest *request,
1215
    uint8_t queued_message_count) {
1216
  return GetResponseFromData(request,
×
1217
                             NULL,
1218
                             0,
1219
                             RDM_ACK,
1220
                             queued_message_count);
×
1221
}
1222

1223
RDMResponse *ResponderHelper::EmptySetResponse(
11✔
1224
    const RDMRequest *request,
1225
    uint8_t queued_message_count) {
1226
  return GetResponseFromData(request,
11✔
1227
                             NULL,
1228
                             0,
1229
                             RDM_ACK,
1230
                             queued_message_count);
11✔
1231
}
1232

1233
RDMResponse *ResponderHelper::SetString(
×
1234
    const RDMRequest *request,
1235
    string *value,
1236
    uint8_t queued_message_count,
1237
    uint8_t max_length) {
1238
  if (request->ParamDataSize() > max_length) {
×
1239
    return NackWithReason(request, NR_FORMAT_ERROR, queued_message_count);
×
1240
  }
1241
  const string new_label(reinterpret_cast<const char*>(request->ParamData()),
×
1242
                         request->ParamDataSize());
×
1243
  *value = new_label;
×
1244
  return EmptySetResponse(request, queued_message_count);
×
1245
}
×
1246

1247
RDMResponse *ResponderHelper::GetBoolValue(const RDMRequest *request,
4✔
1248
                                                 bool value,
1249
                                                 uint8_t queued_message_count) {
1250
  if (request->ParamDataSize()) {
4✔
1251
    return NackWithReason(request, NR_FORMAT_ERROR, queued_message_count);
1✔
1252
  }
1253
  uint8_t param = value ? 1 : 0;
3✔
1254

1255
  return GetResponseFromData(request, &param, sizeof(param),
3✔
1256
                             RDM_ACK, queued_message_count);
1257
}
1258

1259
RDMResponse *ResponderHelper::SetBoolValue(const RDMRequest *request,
7✔
1260
                                                 bool *value,
1261
                                                 uint8_t queued_message_count) {
1262
  uint8_t arg;
7✔
1263
  if (!ResponderHelper::ExtractUInt8(request, &arg)) {
7✔
1264
    return NackWithReason(request, NR_FORMAT_ERROR, queued_message_count);
×
1265
  }
1266

1267
  if (arg == 0 || arg == 1) {
7✔
1268
    *value = arg;
7✔
1269
    return EmptySetResponse(request, queued_message_count);
7✔
1270
  } else {
1271
    return NackWithReason(request, NR_DATA_OUT_OF_RANGE, queued_message_count);
×
1272
  }
1273
}
1274

1275
template<typename T>
1276
static RDMResponse *GenericGetIntValue(const RDMRequest *request,
×
1277
                                             T value,
1278
                                             uint8_t queued_message_count = 0) {
1279
  if (request->ParamDataSize()) {
×
1280
    return NackWithReason(request, NR_FORMAT_ERROR, queued_message_count);
×
1281
  }
1282
  T param = HostToNetwork(value);
×
1283
  return GetResponseFromData(
×
1284
    request,
1285
    reinterpret_cast<const uint8_t*>(&param),
1286
    sizeof(param),
1287
    RDM_ACK,
1288
    queued_message_count);
1289
}
1290

1291
RDMResponse *ResponderHelper::GetUInt8Value(
×
1292
    const RDMRequest *request,
1293
    uint8_t value,
1294
    uint8_t queued_message_count) {
1295
  return GenericGetIntValue(request, value, queued_message_count);
×
1296
}
1297

1298
RDMResponse *ResponderHelper::GetUInt16Value(
4✔
1299
    const RDMRequest *request,
1300
    uint16_t value,
1301
    uint8_t queued_message_count) {
1302
  return GenericGetIntValue(request, value, queued_message_count);
4✔
1303
}
1304

1305
RDMResponse *ResponderHelper::GetUInt32Value(
×
1306
    const RDMRequest *request,
1307
    uint32_t value,
1308
    uint8_t queued_message_count) {
1309
  return GenericGetIntValue(request, value, queued_message_count);
×
1310
}
1311

1312
template<typename T>
1313
static RDMResponse *GenericSetIntValue(const RDMRequest *request,
×
1314
                                             T *value,
1315
                                             uint8_t queued_message_count = 0) {
1316
  if (!GenericExtractValue(request, value)) {
×
1317
    return NackWithReason(request, NR_FORMAT_ERROR, queued_message_count);
×
1318
  }
1319
  return ResponderHelper::EmptySetResponse(request, queued_message_count);
×
1320
}
1321

1322
RDMResponse *ResponderHelper::SetUInt8Value(
×
1323
    const RDMRequest *request,
1324
    uint8_t *value,
1325
    uint8_t queued_message_count) {
1326
  return GenericSetIntValue(request, value, queued_message_count);
×
1327
}
1328

1329
RDMResponse *ResponderHelper::SetUInt16Value(
×
1330
    const RDMRequest *request,
1331
    uint16_t *value,
1332
    uint8_t queued_message_count) {
1333
  return GenericSetIntValue(request, value, queued_message_count);
×
1334
}
1335

1336
RDMResponse *ResponderHelper::SetUInt32Value(
×
1337
    const RDMRequest *request,
1338
    uint32_t *value,
1339
    uint8_t queued_message_count) {
1340
  return GenericSetIntValue(request, value, queued_message_count);
×
1341
}
1342

1343

1344
bool ResponderHelper::FindInterface(
×
1345
    const NetworkManagerInterface *network_manager,
1346
    Interface *interface, uint32_t index) {
1347
  if (!IsInterfaceIndexValid(index)) {
×
1348
    // Invalid index
1349
    return false;
1350
  }
1351

1352
  InterfacePicker::Options options;
×
1353
  options.specific_only = true;
×
1354
  return network_manager->GetInterfacePicker()->ChooseInterface(
×
1355
      interface, index, options);
1356
}
1357

1358
bool ResponderHelper::IsInterfaceIndexValid(uint32_t index) {
4✔
1359
  return (index >= MIN_RDM_INTERFACE_INDEX &&
4✔
1360
          index <= MAX_RDM_INTERFACE_INDEX);
4✔
1361
}
1362

1363
bool ResponderHelper::IsInterfaceIndexValidInterface(Interface interface) {
4✔
1364
  return IsInterfaceIndexValid(interface.index);
4✔
1365
}
1366
}  // namespace rdm
1367
}  // 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

© 2026 Coveralls, Inc