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

OpenLightingProject / ola / 24609073669

18 Apr 2026 04:36PM UTC coverage: 44.864% (-0.9%) from 45.72%
24609073669

push

github

web-flow
Merge pull request #2043 from peternewman/nortle-ftdi

Revert some stuff via 146cf26 which accidentally snuck into #1999 by mistake

8554 of 19846 branches covered (43.1%)

22105 of 49271 relevant lines covered (44.86%)

48.53 hits per line

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

96.6
/common/utils/DmxBuffer.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
 * DmxBuffer.cpp
17
 * The DmxBuffer class
18
 * Copyright (C) 2005 Simon Newton
19
 *
20
 * This implements a DmxBuffer which uses copy-on-write and delayed init.
21
 *
22
 * A DmxBuffer can hold up to 512 bytes of channel information. The amount of
23
 * valid data is returned by calling Size().
24
 */
25

26
/**
27
 * @file DmxBuffer.cpp
28
 */
29

30
#include <string.h>
31
#include <algorithm>
32
#include <iostream>
33
#include <string>
34
#include <vector>
35
#include "ola/Constants.h"
36
#include "ola/DmxBuffer.h"
37
#include "ola/Logging.h"
38
#include "ola/StringUtils.h"
39

40
namespace ola {
41

42
using std::min;
43
using std::max;
44
using std::string;
45
using std::vector;
46

47
DmxBuffer::DmxBuffer()
692✔
48
    : m_ref_count(NULL),
692✔
49
      m_copy_on_write(false),
692✔
50
      m_data(NULL),
692✔
51
      m_length(0) {
692✔
52
}
692✔
53

54

55
DmxBuffer::DmxBuffer(const DmxBuffer &other)
17✔
56
    : m_ref_count(NULL),
17✔
57
      m_copy_on_write(false),
17✔
58
      m_data(NULL),
17✔
59
      m_length(0) {
17✔
60

61
  if (other.m_data && other.m_ref_count) {
17✔
62
    CopyFromOther(other);
16✔
63
  }
64
}
17✔
65

66

67
DmxBuffer::DmxBuffer(const uint8_t *data, unsigned int length)
40✔
68
    : m_ref_count(0),
40✔
69
      m_copy_on_write(false),
40✔
70
      m_data(NULL),
40✔
71
      m_length(0) {
40✔
72
  Set(data, length);
40✔
73
}
40✔
74

75

76
DmxBuffer::DmxBuffer(const string &data)
13✔
77
    : m_ref_count(0),
13✔
78
      m_copy_on_write(false),
13✔
79
      m_data(NULL),
13✔
80
      m_length(0) {
13✔
81
    Set(data);
13✔
82
}
13✔
83

84

85
DmxBuffer::~DmxBuffer() {
762✔
86
  CleanupMemory();
762✔
87
}
762✔
88

89

90
DmxBuffer& DmxBuffer::operator=(const DmxBuffer &other) {
183✔
91
  if (this != &other) {
183✔
92
    CleanupMemory();
182✔
93
    if (other.m_data) {
182✔
94
      CopyFromOther(other);
178✔
95
    }
96
  }
97
  return *this;
183✔
98
}
99

100

101
bool DmxBuffer::operator==(const DmxBuffer &other) const {
67✔
102
  return (m_length == other.m_length &&
67✔
103
          (m_data == other.m_data ||
65✔
104
           0 == memcmp(m_data, other.m_data, m_length)));
54✔
105
}
106

107

108
bool DmxBuffer::operator!=(const DmxBuffer &other) const {
2✔
109
  return !(*this == other);
2✔
110
}
111

112

113
unsigned int DmxBuffer::AdditiveChecksum() const {
3✔
114
  unsigned int checksum = 0;
3✔
115
  for (unsigned int i = 0; i < Size(); i++) {
20✔
116
    checksum += m_data[i];
17✔
117
  }
118
  return checksum;
3✔
119
}
120

121

122
bool DmxBuffer::HTPMerge(const DmxBuffer &other) {
16✔
123
  if (!m_data) {
16✔
124
    if (!Init())
1✔
125
      return false;
126
  }
127
  DuplicateIfNeeded();
16✔
128

129
  unsigned int other_length = min((unsigned int) DMX_UNIVERSE_SIZE,
16✔
130
                                  other.m_length);
16✔
131
  unsigned int merge_length = min(m_length, other.m_length);
16✔
132

133
  for (unsigned int i = 0; i < merge_length; i++) {
63✔
134
    m_data[i] = max(m_data[i], other.m_data[i]);
69✔
135
  }
136

137
  if (other_length > m_length) {
16✔
138
    memcpy(m_data + merge_length, other.m_data + merge_length,
8✔
139
           other_length - merge_length);
8✔
140
    m_length = other_length;
8✔
141
  }
142
  return true;
×
143
}
144

145

146
bool DmxBuffer::Set(const uint8_t *data, unsigned int length) {
134✔
147
  if (!data)
134✔
148
    return false;
149

150
  if (m_copy_on_write)
133✔
151
    CleanupMemory();
4✔
152
  if (!m_data) {
133✔
153
    if (!Init())
103✔
154
      return false;
155
  }
156
  m_length = min(length, (unsigned int) DMX_UNIVERSE_SIZE);
133✔
157
  memcpy(m_data, data, m_length);
133✔
158
  return true;
133✔
159
}
160

161

162
bool DmxBuffer::Set(const string &data) {
30✔
163
  return Set(reinterpret_cast<const uint8_t*>(data.data()), data.length());
30✔
164
}
165

166

167
bool DmxBuffer::Set(const DmxBuffer &other) {
21✔
168
  return Set(other.m_data, other.m_length);
21✔
169
}
170

171

172
bool DmxBuffer::SetFromString(const string &input) {
170✔
173
  unsigned int i = 0;
170✔
174
  vector<string> dmx_values;
170✔
175
  vector<string>::const_iterator iter;
170✔
176

177
  if (m_copy_on_write)
170✔
178
    CleanupMemory();
3✔
179
  if (!m_data)
170✔
180
    if (!Init())
108✔
181
      return false;
182

183
  if (input.empty()) {
170✔
184
    m_length = 0;
1✔
185
    return true;
1✔
186
  }
187
  StringSplit(input, &dmx_values, ",");
169✔
188
  for (iter = dmx_values.begin();
169✔
189
      iter != dmx_values.end() && i < DMX_UNIVERSE_SIZE; ++iter, ++i) {
25,196✔
190
    m_data[i] = atoi(iter->data());
25,027✔
191
  }
192
  m_length = i;
169✔
193
  return true;
169✔
194
}
170✔
195

196

197
bool DmxBuffer::SetRangeToValue(unsigned int offset,
40✔
198
                                uint8_t value,
199
                                unsigned int length) {
200
  if (offset >= DMX_UNIVERSE_SIZE)
40✔
201
    return false;
202

203
  if (!m_data) {
39✔
204
    Blackout();
6✔
205
  }
206

207
  if (offset > m_length)
39✔
208
    return false;
209

210
  DuplicateIfNeeded();
39✔
211

212
  unsigned int copy_length = min(length, DMX_UNIVERSE_SIZE - offset);
39✔
213
  memset(m_data + offset, value, copy_length);
39✔
214
  m_length = max(m_length, offset + copy_length);
39✔
215
  return true;
39✔
216
}
217

218

219
bool DmxBuffer::SetRange(unsigned int offset,
29✔
220
                         const uint8_t *data,
221
                         unsigned int length) {
222
  if (!data || offset >= DMX_UNIVERSE_SIZE)
29✔
223
    return false;
224

225
  if (!m_data) {
27✔
226
    Blackout();
4✔
227
  }
228

229
  if (offset > m_length)
27✔
230
    return false;
231

232
  DuplicateIfNeeded();
25✔
233

234
  unsigned int copy_length = min(length, DMX_UNIVERSE_SIZE - offset);
25✔
235
  memcpy(m_data + offset, data, copy_length);
25✔
236
  m_length = max(m_length, offset + copy_length);
25✔
237
  return true;
25✔
238
}
239

240

241
void DmxBuffer::SetChannel(unsigned int channel, uint8_t data) {
28✔
242
  if (channel >= DMX_UNIVERSE_SIZE)
28✔
243
    return;
244

245
  if (!m_data) {
27✔
246
    Blackout();
3✔
247
  }
248

249
  if (channel > m_length) {
27✔
250
    OLA_WARN << "Attempting to set channel " << channel << " when length is "
4✔
251
             << m_length;
2✔
252
    return;
2✔
253
  }
254

255
  DuplicateIfNeeded();
25✔
256
  m_data[channel] = data;
25✔
257
  m_length = max(channel+1, m_length);
25✔
258
}
259

260

261
void DmxBuffer::Get(uint8_t *data, unsigned int *length) const {
32✔
262
  if (m_data) {
32✔
263
    *length = min(*length, m_length);
27✔
264
    memcpy(data, m_data, *length);
27✔
265
  } else {
266
    *length = 0;
5✔
267
  }
268
}
32✔
269

270

271
void DmxBuffer::GetRange(unsigned int slot, uint8_t *data,
13✔
272
                         unsigned int *length) const {
273
  if (slot >= m_length) {
13✔
274
    *length = 0;
×
275
    return;
×
276
  }
277

278
  if (m_data) {
13✔
279
    *length = min(*length, m_length - slot);
13✔
280
    memcpy(data, m_data + slot, *length);
13✔
281
  } else {
282
    *length = 0;
×
283
  }
284
}
285

286

287
uint8_t DmxBuffer::Get(unsigned int channel) const {
4,246✔
288
  if (m_data && channel < m_length) {
4,246✔
289
    return m_data[channel];
4,244✔
290
  } else {
291
    return 0;
292
  }
293
}
294

295

296
string DmxBuffer::Get() const {
32✔
297
  string data;
32✔
298
  data.append(reinterpret_cast<char*>(m_data), m_length);
32✔
299
  return data;
32✔
300
}
×
301

302

303
bool DmxBuffer::Blackout() {
21✔
304
  if (m_copy_on_write) {
21✔
305
    CleanupMemory();
×
306
  }
307
  if (!m_data) {
21✔
308
    if (!Init()) {
21✔
309
      return false;
310
    }
311
  }
312
  memset(m_data, DMX_MIN_SLOT_VALUE, DMX_UNIVERSE_SIZE);
21✔
313
  m_length = DMX_UNIVERSE_SIZE;
21✔
314
  return true;
21✔
315
}
316

317

318
void DmxBuffer::Reset() {
12✔
319
  if (m_data) {
12✔
320
    m_length = 0;
11✔
321
  }
322
}
12✔
323

324

325
string DmxBuffer::ToString() const {
18✔
326
  if (!m_data) {
18✔
327
    return "";
1✔
328
  }
329

330
  // TODO(Peter): Change to the uint8_t version of StringJoin
331
  std::ostringstream str;
17✔
332
  for (unsigned int i = 0; i < Size(); i++) {
120✔
333
    if (i) {
103✔
334
      str << ",";
86✔
335
    }
336
    str << static_cast<int>(m_data[i]);
103✔
337
  }
338
  return str.str();
17✔
339
}
17✔
340

341

342
/*
343
 * Allocate memory
344
 * @return true on success, otherwise raises an exception
345
 */
346
bool DmxBuffer::Init() {
247✔
347
  m_data = new uint8_t[DMX_UNIVERSE_SIZE];
247✔
348
  m_ref_count = new unsigned int;
247✔
349
  m_length = 0;
247✔
350
  *m_ref_count = 1;
247✔
351
  return true;
247✔
352
}
353

354

355
/*
356
 * Called before making a change, this duplicates the data if required.
357
 * @return true on Duplication, and false it duplication was not needed
358
 */
359
bool DmxBuffer::DuplicateIfNeeded() {
105✔
360
  if (m_copy_on_write && *m_ref_count == 1) {
105✔
361
    m_copy_on_write = false;
×
362
  }
363

364
  if (m_copy_on_write && *m_ref_count > 1) {
105✔
365
    unsigned int *old_ref_count = m_ref_count;
14✔
366
    uint8_t *original_data = m_data;
14✔
367
    unsigned int length = m_length;
14✔
368
    m_copy_on_write = false;
14✔
369
    if (Init()) {
14✔
370
      Set(original_data, length);
14✔
371
      (*old_ref_count)--;
14✔
372
      return true;
14✔
373
    }
374
    return false;
375
  }
376
  return true;
377
}
378

379

380
/*
381
 * Setup this buffer to point to the data of the other buffer
382
 * @param other the source buffer
383
 * @pre other.m_data and other.m_ref_count are not NULL
384
 */
385
void DmxBuffer::CopyFromOther(const DmxBuffer &other) {
194✔
386
  m_copy_on_write = true;
194✔
387
  other.m_copy_on_write = true;
194✔
388
  m_ref_count = other.m_ref_count;
194✔
389
  (*m_ref_count)++;
194✔
390
  m_data = other.m_data;
194✔
391
  m_length = other.m_length;
194✔
392
}
194✔
393

394

395
/*
396
 * Decrement the ref count by one and free the memory if required
397
 */
398
void DmxBuffer::CleanupMemory() {
951✔
399
  if (m_ref_count && m_data) {
951✔
400
    (*m_ref_count)--;
427✔
401
    if (!*m_ref_count) {
427✔
402
      delete[] m_data;
247✔
403
      delete m_ref_count;
247✔
404
    }
405
    m_data = NULL;
427✔
406
    m_ref_count = NULL;
427✔
407
    m_length = 0;
427✔
408
  }
409
}
951✔
410

411
std::ostream& operator<<(std::ostream &out, const DmxBuffer &data) {
1✔
412
  return out << data.ToString();
2✔
413
}
414
}  // 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