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

OpenLightingProject / ola / 17141553775

21 Aug 2025 11:23PM UTC coverage: 45.72% (-0.02%) from 45.742%
17141553775

push

github

web-flow
Merge pull request #2014 from peternewman/mac-be

Tidy the Mac OS Endian behaviour

7586 of 17462 branches covered (43.44%)

22424 of 49046 relevant lines covered (45.72%)

53.43 hits per line

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

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

21
#include <time.h>
22
#include <algorithm>
23
#include <iomanip>
24
#include <iostream>
25
#include <limits>
26
#include <map>
27
#include <queue>
28
#include <set>
29
#include <string>
30
#include <utility>
31
#include <vector>
32

33
#include "ola/Callback.h"
34
#include "ola/Constants.h"
35
#include "ola/Logging.h"
36
#include "ola/OlaCallbackClient.h"
37
#include "ola/StringUtils.h"
38
#include "ola/rdm/RDMEnums.h"
39
#include "ola/rdm/RDMHelper.h"
40
#include "ola/rdm/UID.h"
41
#include "ola/rdm/UIDSet.h"
42
#include "ola/thread/Mutex.h"
43
#include "ola/web/Json.h"
44
#include "ola/web/JsonSections.h"
45
#include "olad/OlaServer.h"
46
#include "olad/OladHTTPServer.h"
47
#include "olad/RDMHTTPModule.h"
48

49
namespace ola {
50

51
using ola::OladHTTPServer;
52
using ola::client::OlaUniverse;
53
using ola::client::Result;
54
using ola::http::HTTPRequest;
55
using ola::http::HTTPResponse;
56
using ola::http::HTTPServer;
57
using ola::rdm::UID;
58
using ola::thread::MutexLocker;
59
using ola::web::BoolItem;
60
using ola::web::GenericItem;
61
using ola::web::HiddenItem;
62
using ola::web::JsonArray;
63
using ola::web::JsonObject;
64
using ola::web::JsonSection;
65
using ola::web::SelectItem;
66
using ola::web::StringItem;
67
using ola::web::UIntItem;
68
using std::endl;
69
using std::map;
70
using std::ostringstream;
71
using std::pair;
72
using std::set;
73
using std::string;
74
using std::vector;
75

76

77
const char RDMHTTPModule::BACKEND_DISCONNECTED_ERROR[] =
78
    "Failed to send request, client isn't connected";
79

80
// global URL params
81
const char RDMHTTPModule::HINT_KEY[] = "hint";
82
const char RDMHTTPModule::ID_KEY[] = "id";
83
const char RDMHTTPModule::SECTION_KEY[] = "section";
84
const char RDMHTTPModule::UID_KEY[] = "uid";
85

86
// URL params for particular sections
87
const char RDMHTTPModule::ADDRESS_FIELD[] = "address";
88
const char RDMHTTPModule::DIMMER_MINIMUM_DECREASING_FIELD[] = "min_increasing";
89
const char RDMHTTPModule::DIMMER_MINIMUM_INCREASING_FIELD[] = "min_decreasing";
90
const char RDMHTTPModule::DISPLAY_INVERT_FIELD[] = "invert";
91
const char RDMHTTPModule::GENERIC_BOOL_FIELD[] = "bool";
92
const char RDMHTTPModule::GENERIC_STRING_FIELD[] = "string";
93
const char RDMHTTPModule::GENERIC_UINT_FIELD[] = "int";
94
const char RDMHTTPModule::IDENTIFY_DEVICE_FIELD[] = "identify_device";
95
const char RDMHTTPModule::LABEL_FIELD[] = "label";
96
const char RDMHTTPModule::LANGUAGE_FIELD[] = "language";
97
const char RDMHTTPModule::RECORD_SENSOR_FIELD[] = "record";
98
const char RDMHTTPModule::SUB_DEVICE_FIELD[] = "sub_device";
99

100
// section identifiers
101
const char RDMHTTPModule::BOOT_SOFTWARE_SECTION[] = "boot_software";
102
const char RDMHTTPModule::CLOCK_SECTION[] = "clock";
103
const char RDMHTTPModule::COMMS_STATUS_SECTION[] = "comms_status";
104
const char RDMHTTPModule::CURVE_SECTION[] = "curve";
105
const char RDMHTTPModule::DEVICE_HOURS_SECTION[] = "device_hours";
106
const char RDMHTTPModule::DEVICE_INFO_SECTION[] = "device_info";
107
const char RDMHTTPModule::DEVICE_LABEL_SECTION[] = "device_label";
108
const char RDMHTTPModule::DIMMER_INFO_SECTION[] = "dimmer_info";
109
const char RDMHTTPModule::DIMMER_MAXIMUM_SECTION[] = "dimmer_maximum";
110
const char RDMHTTPModule::DIMMER_MINIMUM_SECTION[] = "dimmer_minimum";
111
const char RDMHTTPModule::DISPLAY_INVERT_SECTION[] = "display_invert";
112
const char RDMHTTPModule::DISPLAY_LEVEL_SECTION[] = "display_level";
113
const char RDMHTTPModule::DMX_ADDRESS_SECTION[] = "dmx_address";
114
const char RDMHTTPModule::DNS_DOMAIN_NAME_SECTION[] = "dns_domain_name";
115
const char RDMHTTPModule::DNS_HOSTNAME_SECTION[] = "dns_hostname";
116
const char RDMHTTPModule::FACTORY_DEFAULTS_SECTION[] = "factory_defaults";
117
const char RDMHTTPModule::IDENTIFY_DEVICE_SECTION[] = "identify_device";
118
const char RDMHTTPModule::LAMP_HOURS_SECTION[] = "lamp_hours";
119
const char RDMHTTPModule::LAMP_MODE_SECTION[] = "lamp_mode";
120
const char RDMHTTPModule::LAMP_STATE_SECTION[] = "lamp_state";
121
const char RDMHTTPModule::LAMP_STRIKES_SECTION[] = "lamp_strikes";
122
const char RDMHTTPModule::LANGUAGE_SECTION[] = "language";
123
const char RDMHTTPModule::MANUFACTURER_LABEL_SECTION[] = "manufacturer_label";
124
const char RDMHTTPModule::PAN_INVERT_SECTION[] = "pan_invert";
125
const char RDMHTTPModule::PAN_TILT_SWAP_SECTION[] = "pan_tilt_swap";
126
const char RDMHTTPModule::PERSONALITY_SECTION[] = "personality";
127
const char RDMHTTPModule::POWER_CYCLES_SECTION[] = "power_cycles";
128
const char RDMHTTPModule::POWER_STATE_SECTION[] = "power_state";
129
const char RDMHTTPModule::PRODUCT_DETAIL_SECTION[] = "product_detail";
130
const char RDMHTTPModule::PROXIED_DEVICES_SECTION[] = "proxied_devices";
131
const char RDMHTTPModule::RESET_DEVICE_SECTION[] = "reset_device";
132
const char RDMHTTPModule::SENSOR_SECTION[] = "sensor";
133
const char RDMHTTPModule::TILT_INVERT_SECTION[] = "tilt_invert";
134

135
// section names
136
const char RDMHTTPModule::BOOT_SOFTWARE_SECTION_NAME[] =
137
  "Boot Software Version";
138
const char RDMHTTPModule::CLOCK_SECTION_NAME[] = "Clock";
139
const char RDMHTTPModule::COMMS_STATUS_SECTION_NAME[] = "Communication Status";
140
const char RDMHTTPModule::CURVE_SECTION_NAME[] = "Dimmer Curve";
141
const char RDMHTTPModule::DEVICE_HOURS_SECTION_NAME[] = "Device Hours";
142
const char RDMHTTPModule::DEVICE_INFO_SECTION_NAME[] = "Device Info";
143
const char RDMHTTPModule::DEVICE_LABEL_SECTION_NAME[] = "Device Label";
144
const char RDMHTTPModule::DIMMER_INFO_SECTION_NAME[] = "Dimmer Info";
145
const char RDMHTTPModule::DIMMER_MAXIMUM_SECTION_NAME[] = "Dimmer Maximum";
146
const char RDMHTTPModule::DIMMER_MINIMUM_SECTION_NAME[] = "Dimmer Minimum";
147
const char RDMHTTPModule::DISPLAY_INVERT_SECTION_NAME[] = "Display Invert";
148
const char RDMHTTPModule::DISPLAY_LEVEL_SECTION_NAME[] = "Display Level";
149
const char RDMHTTPModule::DMX_ADDRESS_SECTION_NAME[] = "DMX Start Address";
150
const char RDMHTTPModule::DNS_DOMAIN_NAME_SECTION_NAME[] = "DNS Domain Name";
151
const char RDMHTTPModule::DNS_HOSTNAME_SECTION_NAME[] = "DNS Hostname";
152
const char RDMHTTPModule::FACTORY_DEFAULTS_SECTION_NAME[] = "Factory Defaults";
153
const char RDMHTTPModule::IDENTIFY_DEVICE_SECTION_NAME[] = "Identify Device";
154
const char RDMHTTPModule::LAMP_HOURS_SECTION_NAME[] = "Lamp Hours";
155
const char RDMHTTPModule::LAMP_MODE_SECTION_NAME[] = "Lamp On Mode";
156
const char RDMHTTPModule::LAMP_STATE_SECTION_NAME[] = "Lamp State";
157
const char RDMHTTPModule::LAMP_STRIKES_SECTION_NAME[] = "Lamp Strikes";
158
const char RDMHTTPModule::LANGUAGE_SECTION_NAME[] = "Language";
159
const char RDMHTTPModule::MANUFACTURER_LABEL_SECTION_NAME[] =
160
  "Manufacturer Label";
161
const char RDMHTTPModule::PAN_INVERT_SECTION_NAME[] = "Pan Invert";
162
const char RDMHTTPModule::PAN_TILT_SWAP_SECTION_NAME[] = "Pan/Tilt Swap";
163
const char RDMHTTPModule::PERSONALITY_SECTION_NAME[] = "DMX Personality";
164
const char RDMHTTPModule::POWER_CYCLES_SECTION_NAME[] = "Device Power Cycles";
165
const char RDMHTTPModule::POWER_STATE_SECTION_NAME[] = "Power State";
166
const char RDMHTTPModule::PRODUCT_DETAIL_SECTION_NAME[] = "Product Details";
167
const char RDMHTTPModule::PROXIED_DEVICES_SECTION_NAME[] = "Proxied Devices";
168
const char RDMHTTPModule::RESET_DEVICE_SECTION_NAME[] = "Reset Device";
169
const char RDMHTTPModule::TILT_INVERT_SECTION_NAME[] = "Tilt Invert";
170

171
RDMHTTPModule::RDMHTTPModule(HTTPServer *http_server,
×
172
                             client::OlaClient *client)
×
173
    : m_server(http_server),
×
174
      m_client(client),
×
175
      m_shim(client),
×
176
      m_rdm_api(&m_shim),
×
177
      m_pid_store(NULL) {
×
178

179
  m_server->RegisterHandler(
×
180
      "/rdm/run_discovery",
181
      NewCallback(this, &RDMHTTPModule::RunRDMDiscovery));
182
  m_server->RegisterHandler(
×
183
      "/json/rdm/uids",
184
      NewCallback(this, &RDMHTTPModule::JsonUIDs));
185
  m_server->RegisterHandler(
×
186
      "/json/rdm/uid_info",
187
      NewCallback(this, &RDMHTTPModule::JsonUIDInfo));
188
  // Deprecated for clarity, use uid_identify_device instead
189
  m_server->RegisterHandler(
×
190
      "/json/rdm/uid_identify",
191
      NewCallback(this, &RDMHTTPModule::JsonUIDIdentifyDevice));
192
  m_server->RegisterHandler(
×
193
      "/json/rdm/uid_identify_device",
194
      NewCallback(this, &RDMHTTPModule::JsonUIDIdentifyDevice));
195
  m_server->RegisterHandler(
×
196
      "/json/rdm/uid_personalities",
197
      NewCallback(this, &RDMHTTPModule::JsonUIDPersonalities));
198
  m_server->RegisterHandler(
×
199
      "/json/rdm/supported_pids",
200
      NewCallback(this, &RDMHTTPModule::JsonSupportedPIDs));
201
  m_server->RegisterHandler(
×
202
      "/json/rdm/supported_sections",
203
      NewCallback(this, &RDMHTTPModule::JsonSupportedSections));
204
  m_server->RegisterHandler(
×
205
      "/json/rdm/section_info",
206
      NewCallback(this, &RDMHTTPModule::JsonSectionInfo));
207
  m_server->RegisterHandler(
×
208
      "/json/rdm/set_section_info",
209
      NewCallback(this, &RDMHTTPModule::JsonSaveSectionInfo));
210
}
×
211

212

213
/*
214
 * Teardown
215
 */
216
RDMHTTPModule::~RDMHTTPModule() {
×
217
  map<unsigned int, uid_resolution_state*>::iterator uid_iter;
×
218
  for (uid_iter = m_universe_uids.begin(); uid_iter != m_universe_uids.end();
×
219
       uid_iter++) {
×
220
    delete uid_iter->second;
×
221
  }
222
  m_universe_uids.clear();
×
223
}
×
224

225
/**
226
 * @brief Can be called while the server is running. Ownership is not transferred.
227
 */
228
void RDMHTTPModule::SetPidStore(const ola::rdm::RootPidStore *pid_store) {
×
229
  MutexLocker lock(&m_pid_store_mu);
×
230
  m_pid_store = pid_store;
×
231
}
×
232

233

234
/**
235
 * @brief Run RDM discovery for a universe
236
 * @param request the HTTPRequest
237
 * @param response the HTTPResponse
238
 * @returns MHD_NO or MHD_YES
239
 */
240
int RDMHTTPModule::RunRDMDiscovery(const HTTPRequest *request,
×
241
                                   HTTPResponse *response) {
242
  if (request->CheckParameterExists(OladHTTPServer::HELP_PARAMETER)) {
×
243
    return OladHTTPServer::ServeUsage(response,
×
244
                                      "?id=[universe]&amp;incremental=true");
245
  }
246
  unsigned int universe_id;
×
247
  if (!CheckForInvalidId(request, &universe_id)) {
×
248
    return OladHTTPServer::ServeHelpRedirect(response);
×
249
  }
250

251
  string incremental_str = request->GetParameter("incremental");
×
252
  bool incremental = incremental_str == "true";
×
253

254
  m_client->RunDiscovery(
×
255
      universe_id,
256
      incremental ? client::DISCOVERY_INCREMENTAL : client::DISCOVERY_FULL,
257
      NewSingleCallback(this, &RDMHTTPModule::HandleUIDList,
258
                        response, universe_id));
259

260
  return MHD_YES;
×
261
}
×
262

263

264
/**
265
 * @brief Return the list of uids for this universe as json
266
 * @param request the HTTPRequest
267
 * @param response the HTTPResponse
268
 * @returns MHD_NO or MHD_YES
269
 */
270
int RDMHTTPModule::JsonUIDs(const HTTPRequest *request,
×
271
                            HTTPResponse *response) {
272
  if (request->CheckParameterExists(OladHTTPServer::HELP_PARAMETER)) {
×
273
    return OladHTTPServer::ServeUsage(response, "?id=[universe]");
×
274
  }
275
  unsigned int universe_id;
×
276
  if (!CheckForInvalidId(request, &universe_id)) {
×
277
    return OladHTTPServer::ServeHelpRedirect(response);
×
278
  }
279

280
  m_client->RunDiscovery(
×
281
      universe_id,
282
      client::DISCOVERY_CACHED,
283
      NewSingleCallback(this,
284
                        &RDMHTTPModule::HandleUIDList,
285
                        response,
286
                        universe_id));
287
  return MHD_YES;
288
}
289

290

291
/**
292
 * @brief Return the device info for this uid.
293
 * @param request the HTTPRequest
294
 * @param response the HTTPResponse
295
 * @returns MHD_NO or MHD_YES
296
 */
297
int RDMHTTPModule::JsonUIDInfo(const HTTPRequest *request,
×
298
                               HTTPResponse *response) {
299
  if (request->CheckParameterExists(OladHTTPServer::HELP_PARAMETER)) {
×
300
    return OladHTTPServer::ServeUsage(response, "?id=[universe]&amp;uid=[uid]");
×
301
  }
302
  unsigned int universe_id;
×
303
  if (!CheckForInvalidId(request, &universe_id)) {
×
304
    return OladHTTPServer::ServeHelpRedirect(response);
×
305
  }
306

307
  UID *uid = NULL;
×
308
  if (!CheckForInvalidUid(request, &uid)) {
×
309
    return OladHTTPServer::ServeHelpRedirect(response);
×
310
  }
311

312
  string error;
×
313
  bool ok = m_rdm_api.GetDeviceInfo(
×
314
      universe_id,
315
      *uid,
316
      ola::rdm::ROOT_RDM_DEVICE,
317
      NewSingleCallback(this,
318
                        &RDMHTTPModule::UIDInfoHandler,
319
                        response),
320
      &error);
321
  delete uid;
×
322

323
  if (!ok) {
×
324
    return m_server->ServeError(response, BACKEND_DISCONNECTED_ERROR);
×
325
  }
326
  return MHD_YES;
327
}
×
328

329

330
/**
331
 * @brief Returns the identify state for the device.
332
 * @param request the HTTPRequest
333
 * @param response the HTTPResponse
334
 * @returns MHD_NO or MHD_YES
335
 */
336
int RDMHTTPModule::JsonUIDIdentifyDevice(const HTTPRequest *request,
×
337
                                         HTTPResponse *response) {
338
  if (request->CheckParameterExists(OladHTTPServer::HELP_PARAMETER)) {
×
339
    return OladHTTPServer::ServeUsage(response, "?id=[universe]&amp;uid=[uid]");
×
340
  }
341
  unsigned int universe_id;
×
342
  if (!CheckForInvalidId(request, &universe_id)) {
×
343
    return OladHTTPServer::ServeHelpRedirect(response);
×
344
  }
345

346
  UID *uid = NULL;
×
347
  if (!CheckForInvalidUid(request, &uid)) {
×
348
    return OladHTTPServer::ServeHelpRedirect(response);
×
349
  }
350

351
  string error;
×
352
  bool ok = m_rdm_api.GetIdentifyDevice(
×
353
      universe_id,
354
      *uid,
355
      ola::rdm::ROOT_RDM_DEVICE,
356
      NewSingleCallback(this,
357
                        &RDMHTTPModule::UIDIdentifyDeviceHandler,
358
                        response),
359
      &error);
360
  delete uid;
×
361

362
  if (!ok) {
×
363
    return m_server->ServeError(response, BACKEND_DISCONNECTED_ERROR);
×
364
  }
365
  return MHD_YES;
366
}
×
367

368

369
/**
370
 * @brief Returns the personalities on the device
371
 * @param request the HTTPRequest
372
 * @param response the HTTPResponse
373
 * @returns MHD_NO or MHD_YES
374
 */
375
int RDMHTTPModule::JsonUIDPersonalities(const HTTPRequest *request,
×
376
                                        HTTPResponse *response) {
377
  if (request->CheckParameterExists(OladHTTPServer::HELP_PARAMETER)) {
×
378
    return OladHTTPServer::ServeUsage(response, "?id=[universe]&amp;uid=[uid]");
×
379
  }
380
  unsigned int universe_id;
×
381
  if (!CheckForInvalidId(request, &universe_id)) {
×
382
    return OladHTTPServer::ServeHelpRedirect(response);
×
383
  }
384

385
  UID *uid = NULL;
×
386
  if (!CheckForInvalidUid(request, &uid)) {
×
387
    return OladHTTPServer::ServeHelpRedirect(response);
×
388
  }
389

390
  string error = GetPersonalities(request, response, universe_id, *uid, false,
×
391
                                  true);
×
392

393
  delete uid;
×
394
  if (!error.empty()) {
×
395
    return m_server->ServeError(response, BACKEND_DISCONNECTED_ERROR + error);
×
396
  }
397
  return MHD_YES;
398
}
×
399

400

401
/**
402
 * @brief Return a list of PIDs supported by this device.
403
 *
404
 * This isn't used by the UI but it's useful for debugging.
405
 * @param request the HTTPRequest
406
 * @param response the HTTPResponse
407
 * @returns MHD_NO or MHD_YES
408
 * @sa JsonSupportedSections
409
 */
410
int RDMHTTPModule::JsonSupportedPIDs(const HTTPRequest *request,
×
411
                                     HTTPResponse *response) {
412
  if (request->CheckParameterExists(OladHTTPServer::HELP_PARAMETER)) {
×
413
    return OladHTTPServer::ServeUsage(response, "?id=[universe]&amp;uid=[uid]");
×
414
  }
415
  unsigned int universe_id;
×
416
  if (!CheckForInvalidId(request, &universe_id)) {
×
417
    return OladHTTPServer::ServeHelpRedirect(response);
×
418
  }
419

420
  UID *uid = NULL;
×
421
  if (!CheckForInvalidUid(request, &uid)) {
×
422
    return OladHTTPServer::ServeHelpRedirect(response);
×
423
  }
424

425
  string error;
×
426
  bool ok = m_rdm_api.GetSupportedParameters(
×
427
      universe_id,
428
      *uid,
429
      ola::rdm::ROOT_RDM_DEVICE,
430
      NewSingleCallback(this,
431
                        &RDMHTTPModule::SupportedParamsHandler,
432
                        response),
433
      &error);
434
  delete uid;
×
435

436
  if (!ok) {
×
437
    return m_server->ServeError(response, BACKEND_DISCONNECTED_ERROR);
×
438
  }
439
  return MHD_YES;
440
}
×
441

442

443
/**
444
 * @brief Return a list of sections to display in the RDM control panel.
445
 *
446
 * We use the response from SUPPORTED_PARAMS and DEVICE_INFO to decide which
447
 * PIDs exist.
448
 * @param request the HTTPRequest
449
 * @param response the HTTPResponse
450
 * @returns MHD_NO or MHD_YES
451
 */
452
int RDMHTTPModule::JsonSupportedSections(const HTTPRequest *request,
×
453
                                         HTTPResponse *response) {
454
  if (request->CheckParameterExists(OladHTTPServer::HELP_PARAMETER)) {
×
455
    return OladHTTPServer::ServeUsage(response, "?id=[universe]&amp;uid=[uid]");
×
456
  }
457

458
  unsigned int universe_id;
×
459
  if (!CheckForInvalidId(request, &universe_id)) {
×
460
    return OladHTTPServer::ServeHelpRedirect(response);
×
461
  }
462

463
  UID *uid = NULL;
×
464
  if (!CheckForInvalidUid(request, &uid)) {
×
465
    return OladHTTPServer::ServeHelpRedirect(response);
×
466
  }
467

468
  string error;
×
469
  bool ok = m_rdm_api.GetSupportedParameters(
×
470
      universe_id,
471
      *uid,
472
      ola::rdm::ROOT_RDM_DEVICE,
473
      NewSingleCallback(this,
×
474
                        &RDMHTTPModule::SupportedSectionsHandler,
475
                        response,
476
                        universe_id,
477
                        *uid),
478
      &error);
479
  delete uid;
×
480

481
  if (!ok) {
×
482
    return m_server->ServeError(response, BACKEND_DISCONNECTED_ERROR);
×
483
  }
484
  return MHD_YES;
485
}
×
486

487

488
/**
489
 * @brief Get the information required to render a section in the RDM
490
 *   controller panel
491
 */
492
int RDMHTTPModule::JsonSectionInfo(const HTTPRequest *request,
×
493
                                   HTTPResponse *response) {
494
  if (request->CheckParameterExists(OladHTTPServer::HELP_PARAMETER)) {
×
495
    return OladHTTPServer::ServeUsage(response, "?id=[universe]&amp;uid=[uid]"
×
496
                                      "&amp;section=[section]<br />See "
497
                                      "/json/rdm/supported_sections for "
498
                                      "sections");
499
  }
500
  unsigned int universe_id;
×
501
  if (!CheckForInvalidId(request, &universe_id)) {
×
502
    return OladHTTPServer::ServeHelpRedirect(response);
×
503
  }
504

505
  UID *uid = NULL;
×
506
  if (!CheckForInvalidUid(request, &uid)) {
×
507
    return OladHTTPServer::ServeHelpRedirect(response);
×
508
  }
509

510
  string section_id = request->GetParameter(SECTION_KEY);
×
511
  string error;
×
512
  if (section_id == PROXIED_DEVICES_SECTION) {
×
513
    error = GetProxiedDevices(response, universe_id, *uid);
×
514
  } else if (section_id == COMMS_STATUS_SECTION) {
×
515
    error = GetCommStatus(response, universe_id, *uid);
×
516
  } else if (section_id == DEVICE_INFO_SECTION) {
×
517
    error = GetDeviceInfo(request, response, universe_id, *uid);
×
518
  } else if (section_id == PRODUCT_DETAIL_SECTION) {
×
519
    error = GetProductIds(request, response, universe_id, *uid);
×
520
  } else if (section_id == MANUFACTURER_LABEL_SECTION) {
×
521
    error = GetManufacturerLabel(request, response, universe_id, *uid);
×
522
  } else if (section_id == DEVICE_LABEL_SECTION) {
×
523
    error = GetDeviceLabel(request, response, universe_id, *uid);
×
524
  } else if (section_id == FACTORY_DEFAULTS_SECTION) {
×
525
    error = GetFactoryDefaults(response, universe_id, *uid);
×
526
  } else if (section_id == LANGUAGE_SECTION) {
×
527
    error = GetLanguage(response, universe_id, *uid);
×
528
  } else if (section_id == BOOT_SOFTWARE_SECTION) {
×
529
    error = GetBootSoftware(response, universe_id, *uid);
×
530
  } else if (section_id == PERSONALITY_SECTION) {
×
531
    error = GetPersonalities(request, response, universe_id, *uid, true);
×
532
  } else if (section_id == DMX_ADDRESS_SECTION) {
×
533
    error = GetStartAddress(request, response, universe_id, *uid);
×
534
  } else if (section_id == SENSOR_SECTION) {
×
535
    error = GetSensor(request, response, universe_id, *uid);
×
536
  } else if (section_id == DEVICE_HOURS_SECTION) {
×
537
    error = GetDeviceHours(request, response, universe_id, *uid);
×
538
  } else if (section_id == LAMP_HOURS_SECTION) {
×
539
    error = GetLampHours(request, response, universe_id, *uid);
×
540
  } else if (section_id == LAMP_MODE_SECTION) {
×
541
    error = GetLampMode(request, response, universe_id, *uid);
×
542
  } else if (section_id == LAMP_STATE_SECTION) {
×
543
    error = GetLampState(request, response, universe_id, *uid);
×
544
  } else if (section_id == LAMP_STRIKES_SECTION) {
×
545
    error = GetLampStrikes(request, response, universe_id, *uid);
×
546
  } else if (section_id == POWER_CYCLES_SECTION) {
×
547
    error = GetPowerCycles(request, response, universe_id, *uid);
×
548
  } else if (section_id == DISPLAY_INVERT_SECTION) {
×
549
    error = GetDisplayInvert(response, universe_id, *uid);
×
550
  } else if (section_id == DISPLAY_LEVEL_SECTION) {
×
551
    error = GetDisplayLevel(response, universe_id, *uid);
×
552
  } else if (section_id == PAN_INVERT_SECTION) {
×
553
    error = GetPanInvert(response, universe_id, *uid);
×
554
  } else if (section_id == TILT_INVERT_SECTION) {
×
555
    error = GetTiltInvert(response, universe_id, *uid);
×
556
  } else if (section_id == PAN_TILT_SWAP_SECTION) {
×
557
    error = GetPanTiltSwap(response, universe_id, *uid);
×
558
  } else if (section_id == CLOCK_SECTION) {
×
559
    error = GetClock(response, universe_id, *uid);
×
560
  } else if (section_id == IDENTIFY_DEVICE_SECTION) {
×
561
    error = GetIdentifyDevice(response, universe_id, *uid);
×
562
  } else if (section_id == POWER_STATE_SECTION) {
×
563
    error = GetPowerState(response, universe_id, *uid);
×
564
  } else if (section_id == RESET_DEVICE_SECTION) {
×
565
    // No get command available, so just generate the JSON
566
    error = GetResetDevice(response);
×
567
  } else if (section_id == DNS_HOSTNAME_SECTION) {
×
568
    error = GetDnsHostname(response, universe_id, *uid);
×
569
  } else if (section_id == DNS_DOMAIN_NAME_SECTION) {
×
570
    error = GetDnsDomainName(response, universe_id, *uid);
×
571
  } else if (section_id == CURVE_SECTION) {
×
572
    error = GetCurve(request, response, universe_id, *uid, true);
×
573
  } else if (section_id == DIMMER_INFO_SECTION) {
×
574
    error = GetDimmerInfo(response, universe_id, *uid);
×
575
  } else if (section_id == DIMMER_MINIMUM_SECTION) {
×
576
    error = GetDimmerMinimumLevels(response, universe_id, *uid);
×
577
  } else if (section_id == DIMMER_MAXIMUM_SECTION) {
×
578
    error = GetDimmerMaximumLevel(response, universe_id, *uid);
×
579
  } else {
580
    OLA_INFO << "Missing or unknown section id: " << section_id;
×
581
    delete uid;
×
582
    return OladHTTPServer::ServeHelpRedirect(response);
×
583
  }
584

585
  delete uid;
×
586
  if (!error.empty()) {
×
587
    return m_server->ServeError(response, BACKEND_DISCONNECTED_ERROR + error);
×
588
  }
589
  return MHD_YES;
590
}
×
591

592

593
/**
594
 * Save the information for a section or item.
595
 */
596
int RDMHTTPModule::JsonSaveSectionInfo(const HTTPRequest *request,
×
597
                                       HTTPResponse *response) {
598
  if (request->CheckParameterExists(OladHTTPServer::HELP_PARAMETER)) {
×
599
    return OladHTTPServer::ServeUsage(response, "?id=[universe]&amp;uid=[uid]"
×
600
                                      "&amp;section=[section]<br />See "
601
                                      "/json/rdm/supported_sections for "
602
                                      "sections");
603
  }
604
  unsigned int universe_id;
×
605
  if (!CheckForInvalidId(request, &universe_id)) {
×
606
    return OladHTTPServer::ServeHelpRedirect(response);
×
607
  }
608

609
  UID *uid = NULL;
×
610
  if (!CheckForInvalidUid(request, &uid)) {
×
611
    return OladHTTPServer::ServeHelpRedirect(response);
×
612
  }
613

614
  string section_id = request->GetParameter(SECTION_KEY);
×
615
  string error;
×
616
  if (section_id == DEVICE_LABEL_SECTION) {
×
617
    error = SetDeviceLabel(request, response, universe_id, *uid);
×
618
  } else if (section_id == COMMS_STATUS_SECTION) {
×
619
    error = ClearCommsCounters(response, universe_id, *uid);
×
620
  } else if (section_id == FACTORY_DEFAULTS_SECTION) {
×
621
    error = SetFactoryDefault(response, universe_id, *uid);
×
622
  } else if (section_id == LANGUAGE_SECTION) {
×
623
    error = SetLanguage(request, response, universe_id, *uid);
×
624
  } else if (section_id == PERSONALITY_SECTION) {
×
625
    error = SetPersonality(request, response, universe_id, *uid);
×
626
  } else if (section_id == DMX_ADDRESS_SECTION) {
×
627
    error = SetStartAddress(request, response, universe_id, *uid);
×
628
  } else if (section_id == SENSOR_SECTION) {
×
629
    error = RecordSensor(request, response, universe_id, *uid);
×
630
  } else if (section_id == DEVICE_HOURS_SECTION) {
×
631
    error = SetDeviceHours(request, response, universe_id, *uid);
×
632
  } else if (section_id == LAMP_HOURS_SECTION) {
×
633
    error = SetLampHours(request, response, universe_id, *uid);
×
634
  } else if (section_id == LAMP_MODE_SECTION) {
×
635
    error = SetLampMode(request, response, universe_id, *uid);
×
636
  } else if (section_id == LAMP_STATE_SECTION) {
×
637
    error = SetLampState(request, response, universe_id, *uid);
×
638
  } else if (section_id == LAMP_STRIKES_SECTION) {
×
639
    error = SetLampStrikes(request, response, universe_id, *uid);
×
640
  } else if (section_id == POWER_CYCLES_SECTION) {
×
641
    error = SetPowerCycles(request, response, universe_id, *uid);
×
642
  } else if (section_id == DISPLAY_INVERT_SECTION) {
×
643
    error = SetDisplayInvert(request, response, universe_id, *uid);
×
644
  } else if (section_id == DISPLAY_LEVEL_SECTION) {
×
645
    error = SetDisplayLevel(request, response, universe_id, *uid);
×
646
  } else if (section_id == PAN_INVERT_SECTION) {
×
647
    error = SetPanInvert(request, response, universe_id, *uid);
×
648
  } else if (section_id == TILT_INVERT_SECTION) {
×
649
    error = SetTiltInvert(request, response, universe_id, *uid);
×
650
  } else if (section_id == PAN_TILT_SWAP_SECTION) {
×
651
    error = SetPanTiltSwap(request, response, universe_id, *uid);
×
652
  } else if (section_id == CLOCK_SECTION) {
×
653
    error = SyncClock(response, universe_id, *uid);
×
654
  } else if (section_id == IDENTIFY_DEVICE_SECTION) {
×
655
    error = SetIdentifyDevice(request, response, universe_id, *uid);
×
656
  } else if (section_id == POWER_STATE_SECTION) {
×
657
    error = SetPowerState(request, response, universe_id, *uid);
×
658
  } else if (section_id == RESET_DEVICE_SECTION) {
×
659
    error = SetResetDevice(request, response, universe_id, *uid);
×
660
  } else if (section_id == DNS_HOSTNAME_SECTION) {
×
661
    error = SetDnsHostname(request, response, universe_id, *uid);
×
662
  } else if (section_id == DNS_DOMAIN_NAME_SECTION) {
×
663
    error = SetDnsDomainName(request, response, universe_id, *uid);
×
664
  } else if (section_id == CURVE_SECTION) {
×
665
    error = SetCurve(request, response, universe_id, *uid);
×
666
  } else if (section_id == DIMMER_MINIMUM_SECTION) {
×
667
    error = SetDimmerMinimumLevels(request, response, universe_id, *uid);
×
668
  } else if (section_id == DIMMER_MAXIMUM_SECTION) {
×
669
    error = SetDimmerMaximumLevel(request, response, universe_id, *uid);
×
670
  } else {
671
    OLA_INFO << "Missing or unknown section id: " << section_id;
×
672
    delete uid;
×
673
    return OladHTTPServer::ServeHelpRedirect(response);
×
674
  }
675

676
  delete uid;
×
677
  if (!error.empty()) {
×
678
    return RespondWithError(response, error);
×
679
  }
680
  return MHD_YES;
681
}
×
682

683

684
/**
685
 * This is called from the main http server whenever a new list of active
686
 * universes is received. It's used to prune the uid map so we don't bother
687
 * trying to resolve uids for universes that no longer exist.
688
 */
689
void RDMHTTPModule::PruneUniverseList(const vector<OlaUniverse> &universes) {
×
690
  map<unsigned int, uid_resolution_state*>::iterator uid_iter;
×
691
  for (uid_iter = m_universe_uids.begin(); uid_iter != m_universe_uids.end();
×
692
       uid_iter++) {
×
693
    uid_iter->second->active = false;
×
694
  }
695

696
  vector<OlaUniverse>::const_iterator iter;
×
697
  for (iter = universes.begin(); iter != universes.end(); ++iter) {
×
698
    uid_iter = m_universe_uids.find(iter->Id());
×
699
    if (uid_iter != m_universe_uids.end()) {
×
700
      uid_iter->second->active = true;
×
701
    }
702
  }
703

704
  // clean up the uid map for those universes that no longer exist
705
  for (uid_iter = m_universe_uids.begin(); uid_iter != m_universe_uids.end();) {
×
706
    if (!uid_iter->second->active) {
×
707
      OLA_DEBUG << "removing " << uid_iter->first << " from the uid map";
×
708
      delete uid_iter->second;
×
709
      m_universe_uids.erase(uid_iter++);
×
710
    } else {
711
      uid_iter++;
×
712
    }
713
  }
714
}
×
715

716

717
/*
718
 * @brief Handle the UID list response.
719
 * @param response the HTTPResponse that is associated with the request.
720
 * @param uids the UIDs for this response.
721
 * @param error an error string.
722
 */
723
void RDMHTTPModule::HandleUIDList(HTTPResponse *response,
×
724
                                  unsigned int universe_id,
725
                                  const Result &result,
726
                                  const ola::rdm::UIDSet &uids) {
727
  if (!result.Success()) {
×
728
    m_server->ServeError(response, result.Error());
×
729
    return;
×
730
  }
731
  ola::rdm::UIDSet::Iterator iter = uids.Begin();
×
732
  uid_resolution_state *uid_state = GetUniverseUidsOrCreate(universe_id);
×
733

734
  // mark all uids as inactive so we can remove the unused ones at the end
735
  map<UID, resolved_uid>::iterator uid_iter;
×
736
  for (uid_iter = uid_state->resolved_uids.begin();
×
737
       uid_iter != uid_state->resolved_uids.end(); ++uid_iter)
×
738
    uid_iter->second.active = false;
×
739

740
  JsonObject json;
×
741
  json.Add("universe", universe_id);
×
742
  JsonArray *json_uids = json.AddArray("uids");
×
743

744
  for (; iter != uids.End(); ++iter) {
×
745
    uid_iter = uid_state->resolved_uids.find(*iter);
×
746

747
    string manufacturer = "";
×
748
    string device = "";
×
749

750
    if (uid_iter == uid_state->resolved_uids.end()) {
×
751
      // schedule resolution
752
      uid_state->pending_uids.push(std::make_pair(*iter, RESOLVE_MANUFACTURER));
×
753
      uid_state->pending_uids.push(std::make_pair(*iter, RESOLVE_DEVICE));
×
754
      resolved_uid uid_descriptor = {"", "", true};
×
755
      uid_state->resolved_uids[*iter] = uid_descriptor;
×
756
      OLA_INFO << "Adding UID " << *iter << " to resolution queue";
×
757
    } else {
×
758
      manufacturer = uid_iter->second.manufacturer;
×
759
      device = uid_iter->second.device;
×
760
      uid_iter->second.active = true;
×
761
    }
762

763
    JsonObject *json_uid = json_uids->AppendObject();
×
764
    json_uid->Add("manufacturer_id", iter->ManufacturerId());
×
765
    json_uid->Add("device_id", iter->DeviceId());
×
766
    json_uid->Add("device", device);
×
767
    json_uid->Add("manufacturer", manufacturer);
×
768
    json_uid->Add("uid", iter->ToString());
×
769
  }
×
770

771
  response->SetNoCache();
×
772
  response->SetContentType(HTTPServer::CONTENT_TYPE_PLAIN);
×
773
  response->SendJson(json);
×
774
  delete response;
×
775

776
  // remove any old UIDs
777
  for (uid_iter = uid_state->resolved_uids.begin();
×
778
       uid_iter != uid_state->resolved_uids.end();) {
×
779
    if (!uid_iter->second.active) {
×
780
      OLA_INFO << "Removed UID " << uid_iter->first;
×
781
      uid_state->resolved_uids.erase(uid_iter++);
×
782
    } else {
783
      ++uid_iter;
×
784
    }
785
  }
786

787
  if (!uid_state->uid_resolution_running) {
×
788
    ResolveNextUID(universe_id);
×
789
  }
790
}
×
791

792

793
/*
794
 * @brief Send the RDM command needed to resolve the next uid in the queue
795
 * @param universe_id the universe id to resolve the next UID for.
796
 */
797
void RDMHTTPModule::ResolveNextUID(unsigned int universe_id) {
×
798
  bool sent_request = false;
×
799
  string error;
×
800
  uid_resolution_state *uid_state = GetUniverseUids(universe_id);
×
801

802
  if (!uid_state) {
×
803
    return;
804
  }
805

806
  while (!sent_request) {
×
807
    if (uid_state->pending_uids.empty()) {
×
808
      uid_state->uid_resolution_running = false;
×
809
      return;
×
810
    }
811
    uid_state->uid_resolution_running = true;
×
812

813
    pair<UID, uid_resolve_action> &uid_action_pair =
×
814
      uid_state->pending_uids.front();
×
815
    if (uid_action_pair.second == RESOLVE_MANUFACTURER) {
×
816
      OLA_INFO << "sending manufacturer request for " << uid_action_pair.first;
×
817
      sent_request = m_rdm_api.GetManufacturerLabel(
×
818
          universe_id,
819
          uid_action_pair.first,
×
820
          ola::rdm::ROOT_RDM_DEVICE,
821
          NewSingleCallback(this,
×
822
                            &RDMHTTPModule::UpdateUIDManufacturerLabel,
823
                            universe_id,
824
                            uid_action_pair.first),
×
825
          &error);
826
      uid_state->pending_uids.pop();
×
827
    } else if (uid_action_pair.second == RESOLVE_DEVICE) {
×
828
      OLA_INFO << "sending device request for " << uid_action_pair.first;
×
829
      sent_request = m_rdm_api.GetDeviceLabel(
×
830
          universe_id,
831
          uid_action_pair.first,
×
832
          ola::rdm::ROOT_RDM_DEVICE,
833
          NewSingleCallback(this,
×
834
                            &RDMHTTPModule::UpdateUIDDeviceLabel,
835
                            universe_id,
836
                            uid_action_pair.first),
×
837
          &error);
838
      uid_state->pending_uids.pop();
×
839
    } else {
840
      OLA_WARN << "Unknown UID resolve action " <<
×
841
        static_cast<int>(uid_action_pair.second);
×
842
    }
843
  }
844
}
×
845

846
/*
847
 * @brief Handle the manufacturer label response.
848
 */
849
void RDMHTTPModule::UpdateUIDManufacturerLabel(
×
850
    unsigned int universe,
851
    UID uid,
852
    const ola::rdm::ResponseStatus &status,
853
    const string &manufacturer_label) {
854
  uid_resolution_state *uid_state = GetUniverseUids(universe);
×
855

856
  if (!uid_state) {
×
857
    return;
858
  }
859

860
  if (CheckForRDMSuccess(status)) {
×
861
    map<UID, resolved_uid>::iterator uid_iter;
×
862
    uid_iter = uid_state->resolved_uids.find(uid);
×
863
    if (uid_iter != uid_state->resolved_uids.end()) {
×
864
      uid_iter->second.manufacturer = manufacturer_label;
×
865
    }
866
  }
867
  ResolveNextUID(universe);
×
868
}
869

870

871
/*
872
 * @brief Handle the device label response.
873
 */
874
void RDMHTTPModule::UpdateUIDDeviceLabel(
×
875
    unsigned int universe,
876
    UID uid,
877
    const ola::rdm::ResponseStatus &status,
878
    const string &device_label) {
879
  uid_resolution_state *uid_state = GetUniverseUids(universe);
×
880

881
  if (!uid_state) {
×
882
    return;
883
  }
884

885
  if (CheckForRDMSuccess(status)) {
×
886
    map<UID, resolved_uid>::iterator uid_iter;
×
887
    uid_iter = uid_state->resolved_uids.find(uid);
×
888
    if (uid_iter != uid_state->resolved_uids.end()) {
×
889
      uid_iter->second.device = device_label;
×
890
    }
891
  }
892
  ResolveNextUID(universe);
×
893
}
894

895

896
/*
897
 * @brief Get the UID resolution state for a particular universe
898
 * @param universe the id of the universe to get the state for
899
 */
900
RDMHTTPModule::uid_resolution_state *RDMHTTPModule::GetUniverseUids(
×
901
    unsigned int universe) {
902
  map<unsigned int, uid_resolution_state*>::iterator iter =
×
903
    m_universe_uids.find(universe);
×
904
  return iter == m_universe_uids.end() ? NULL : iter->second;
×
905
}
906

907

908
/*
909
 * @brief Get the UID resolution state for a particular universe or create one if it
910
 * doesn't exist.
911
 * @param universe the id of the universe to get the state for
912
 */
913
RDMHTTPModule::uid_resolution_state *RDMHTTPModule::GetUniverseUidsOrCreate(
×
914
    unsigned int universe) {
915
  map<unsigned int, uid_resolution_state*>::iterator iter =
×
916
    m_universe_uids.find(universe);
×
917

918
  if (iter == m_universe_uids.end()) {
×
919
    OLA_DEBUG << "Adding a new state entry for " << universe;
×
920
    uid_resolution_state *state  = new uid_resolution_state();
×
921
    state->uid_resolution_running = false;
×
922
    state->active = true;
×
923
    pair<unsigned int, uid_resolution_state*> p(universe, state);
×
924
    iter = m_universe_uids.insert(p).first;
×
925
  }
926
  return iter->second;
×
927
}
928

929

930
/**
931
 * @brief Handle the Device Info response and build the JSON
932
 */
933
void RDMHTTPModule::UIDInfoHandler(HTTPResponse *response,
×
934
                                   const ola::rdm::ResponseStatus &status,
935
                                   const ola::rdm::DeviceDescriptor &device) {
936
  if (CheckForRDMError(response, status)) {
×
937
    return;
×
938
  }
939

940
  JsonObject json;
×
941
  json.Add("error", "");
×
942
  json.Add("address", device.dmx_start_address);
×
943
  json.Add("footprint", device.dmx_footprint);
×
944
  json.Add("personality", static_cast<int>(device.current_personality));
×
945
  json.Add("personality_count", static_cast<int>(device.personality_count));
×
946

947
  response->SetNoCache();
×
948
  response->SetContentType(HTTPServer::CONTENT_TYPE_PLAIN);
×
949
  response->SendJson(json);
×
950
  delete response;
×
951
}
×
952

953

954
/**
955
 * @brief Handle the identify device response and build the JSON
956
 */
957
void RDMHTTPModule::UIDIdentifyDeviceHandler(
×
958
    HTTPResponse *response,
959
    const ola::rdm::ResponseStatus &status,
960
    bool value) {
961
  if (CheckForRDMError(response, status)) {
×
962
    return;
×
963
  }
964

965
  JsonObject json;
×
966
  json.Add("error", "");
×
967
  json.Add("identify_device", value);
×
968

969
  response->SetNoCache();
×
970
  response->SetContentType(HTTPServer::CONTENT_TYPE_PLAIN);
×
971
  response->SendJson(json);
×
972
  delete response;
×
973
}
×
974

975

976
/**
977
 * @brief Send the response to a DMX personality section
978
 */
979
void RDMHTTPModule::SendPersonalityResponse(HTTPResponse *response,
×
980
                                            personality_info *info) {
981
  JsonObject json;
×
982
  json.Add("error", "");
×
983
  JsonArray *personalities = json.AddArray("personalities");
×
984

985
  unsigned int i = 1;
×
986
  while (i <= info->total && i <= info->personalities.size()) {
×
987
    if (info->personalities[i - 1].first != INVALID_PERSONALITY) {
×
988
      JsonObject *personality = personalities->AppendObject();
×
989
      personality->Add("name", info->personalities[i - 1].second);
×
990
      personality->Add("index", i);
×
991
      personality->Add("footprint", info->personalities[i - 1].first);
×
992
    }
993
    i++;
×
994
  }
995
  json.Add("selected", info->active);
×
996

997
  response->SetNoCache();
×
998
  response->SetContentType(HTTPServer::CONTENT_TYPE_PLAIN);
×
999
  response->SendJson(json);
×
1000
  delete info->uid;
×
1001
  delete info;
×
1002
}
×
1003

1004

1005
/*
1006
 * @brief Handle the response from a supported params request
1007
 */
1008
void RDMHTTPModule::SupportedParamsHandler(
×
1009
    HTTPResponse *response,
1010
    const ola::rdm::ResponseStatus &status,
1011
    const vector<uint16_t> &pids) {
1012
  JsonObject json;
×
1013
  if (CheckForRDMSuccess(status)) {
×
1014
    JsonArray *pids_json = json.AddArray("pids");
×
1015
    vector<uint16_t>::const_iterator iter = pids.begin();
×
1016
    for (; iter != pids.end(); ++iter)
×
1017
      pids_json->Append(*iter);
×
1018
  }
1019

1020
  response->SetNoCache();
×
1021
  response->SetContentType(HTTPServer::CONTENT_TYPE_PLAIN);
×
1022
  response->SendJson(json);
×
1023
  delete response;
×
1024
}
×
1025

1026

1027
/**
1028
 * @brief Takes the supported PIDs for a device and come up with the list of
1029
 * sections to display in the RDM panel
1030
 */
1031
void RDMHTTPModule::SupportedSectionsHandler(
×
1032
    HTTPResponse *response,
1033
    unsigned int universe_id,
1034
    UID uid,
1035
    const ola::rdm::ResponseStatus &status,
1036
    const vector<uint16_t> &pid_list) {
1037
  string error;
×
1038

1039
  // nacks here are ok if the device doesn't support SUPPORTED_PARAMS
1040
  if (!CheckForRDMSuccess(status) && !status.WasNacked()) {
×
1041
    m_server->ServeError(response, BACKEND_DISCONNECTED_ERROR + error);
×
1042
    return;
×
1043
  }
1044

1045
  m_rdm_api.GetDeviceInfo(
×
1046
      universe_id,
1047
      uid,
1048
      ola::rdm::ROOT_RDM_DEVICE,
1049
      NewSingleCallback(this,
×
1050
                        &RDMHTTPModule::SupportedSectionsDeviceInfoHandler,
1051
                        response,
1052
                        pid_list),
1053
      &error);
1054
  if (!error.empty())
×
1055
    m_server->ServeError(response, BACKEND_DISCONNECTED_ERROR + error);
×
1056
}
×
1057

1058

1059
/**
1060
 * @brief Handle the second part of the supported sections request.
1061
 */
1062
void RDMHTTPModule::SupportedSectionsDeviceInfoHandler(
×
1063
    HTTPResponse *response,
1064
    const vector<uint16_t> pid_list,
1065
    const ola::rdm::ResponseStatus &status,
1066
    const ola::rdm::DeviceDescriptor &device) {
1067
  vector<section_info> sections;
×
1068
  std::set<uint16_t> pids;
×
1069
  copy(pid_list.begin(), pid_list.end(), inserter(pids, pids.end()));
×
1070

1071
  // PID_DEVICE_INFO is required so we always add it
1072
  string hint;
×
1073
  if (pids.find(ola::rdm::PID_DEVICE_MODEL_DESCRIPTION) != pids.end()) {
×
1074
      hint.push_back('m');  // m is for device model
×
1075
  }
1076

1077
  AddSection(&sections, DEVICE_INFO_SECTION, DEVICE_INFO_SECTION_NAME, hint);
×
1078

1079
  AddSection(&sections, IDENTIFY_DEVICE_SECTION, IDENTIFY_DEVICE_SECTION_NAME);
×
1080

1081
  bool dmx_address_added = false;
×
1082
  bool include_software_version = false;
×
1083
  set<uint16_t>::const_iterator iter = pids.begin();
×
1084
  for (; iter != pids.end(); ++iter) {
×
1085
    switch (*iter) {
×
1086
      case ola::rdm::PID_PROXIED_DEVICES:
×
1087
        AddSection(&sections, PROXIED_DEVICES_SECTION,
×
1088
                   PROXIED_DEVICES_SECTION_NAME);
1089
        break;
×
1090
      case ola::rdm::PID_COMMS_STATUS:
×
1091
        AddSection(&sections, COMMS_STATUS_SECTION, COMMS_STATUS_SECTION_NAME);
×
1092
        break;
×
1093
      case ola::rdm::PID_PRODUCT_DETAIL_ID_LIST:
×
1094
        AddSection(&sections, PRODUCT_DETAIL_SECTION,
×
1095
                   PRODUCT_DETAIL_SECTION_NAME);
1096
        break;
×
1097
      case ola::rdm::PID_MANUFACTURER_LABEL:
×
1098
        AddSection(&sections, MANUFACTURER_LABEL_SECTION,
×
1099
                   MANUFACTURER_LABEL_SECTION_NAME);
1100
        break;
×
1101
      case ola::rdm::PID_DEVICE_LABEL:
×
1102
        AddSection(&sections, DEVICE_LABEL_SECTION, DEVICE_LABEL_SECTION_NAME);
×
1103
        break;
×
1104
      case ola::rdm::PID_FACTORY_DEFAULTS:
×
1105
        AddSection(&sections, FACTORY_DEFAULTS_SECTION,
×
1106
                   FACTORY_DEFAULTS_SECTION_NAME);
1107
        break;
×
1108
      case ola::rdm::PID_LANGUAGE:
×
1109
        AddSection(&sections, LANGUAGE_SECTION, LANGUAGE_SECTION_NAME);
×
1110
        break;
×
1111
      case ola::rdm::PID_BOOT_SOFTWARE_VERSION_ID:
1112
      case ola::rdm::PID_BOOT_SOFTWARE_VERSION_LABEL:
1113
        include_software_version = true;
×
1114
        break;
1115
      case ola::rdm::PID_DMX_PERSONALITY:
×
1116
        if (pids.find(ola::rdm::PID_DMX_PERSONALITY_DESCRIPTION) ==
×
1117
            pids.end()) {
×
1118
          AddSection(&sections, PERSONALITY_SECTION, PERSONALITY_SECTION_NAME);
×
1119
        } else {
1120
          AddSection(&sections, PERSONALITY_SECTION, PERSONALITY_SECTION_NAME,
×
1121
                     "l");
1122
        }
1123
        break;
1124
      case ola::rdm::PID_DMX_START_ADDRESS:
×
1125
        AddSection(&sections, DMX_ADDRESS_SECTION, DMX_ADDRESS_SECTION_NAME);
×
1126
        dmx_address_added = true;
×
1127
        break;
×
1128
      case ola::rdm::PID_DEVICE_HOURS:
×
1129
        AddSection(&sections, DEVICE_HOURS_SECTION, DEVICE_HOURS_SECTION_NAME);
×
1130
        break;
×
1131
      case ola::rdm::PID_LAMP_HOURS:
×
1132
        AddSection(&sections, LAMP_HOURS_SECTION, LAMP_HOURS_SECTION_NAME);
×
1133
        break;
×
1134
      case ola::rdm::PID_LAMP_STRIKES:
×
1135
        AddSection(&sections, LAMP_STRIKES_SECTION, LAMP_STRIKES_SECTION_NAME);
×
1136
        break;
×
1137
      case ola::rdm::PID_LAMP_STATE:
×
1138
        AddSection(&sections, LAMP_STATE_SECTION, LAMP_STATE_SECTION_NAME);
×
1139
        break;
×
1140
      case ola::rdm::PID_LAMP_ON_MODE:
×
1141
        AddSection(&sections, LAMP_MODE_SECTION, LAMP_MODE_SECTION_NAME);
×
1142
        break;
×
1143
      case ola::rdm::PID_DEVICE_POWER_CYCLES:
×
1144
        AddSection(&sections, POWER_CYCLES_SECTION, POWER_CYCLES_SECTION_NAME);
×
1145
        break;
×
1146
      case ola::rdm::PID_DISPLAY_INVERT:
×
1147
        AddSection(&sections, DISPLAY_INVERT_SECTION,
×
1148
                   DISPLAY_INVERT_SECTION_NAME);
1149
        break;
×
1150
      case ola::rdm::PID_DISPLAY_LEVEL:
×
1151
        AddSection(&sections, DISPLAY_LEVEL_SECTION,
×
1152
                   DISPLAY_LEVEL_SECTION_NAME);
1153
        break;
×
1154
      case ola::rdm::PID_PAN_INVERT:
×
1155
        AddSection(&sections, PAN_INVERT_SECTION, PAN_INVERT_SECTION_NAME);
×
1156
        break;
×
1157
      case ola::rdm::PID_TILT_INVERT:
×
1158
        AddSection(&sections, TILT_INVERT_SECTION, TILT_INVERT_SECTION_NAME);
×
1159
        break;
×
1160
      case ola::rdm::PID_PAN_TILT_SWAP:
×
1161
        AddSection(&sections, PAN_TILT_SWAP_SECTION,
×
1162
                   PAN_TILT_SWAP_SECTION_NAME);
1163
        break;
×
1164
      case ola::rdm::PID_REAL_TIME_CLOCK:
×
1165
        AddSection(&sections, CLOCK_SECTION, CLOCK_SECTION_NAME);
×
1166
        break;
×
1167
      case ola::rdm::PID_POWER_STATE:
×
1168
        AddSection(&sections, POWER_STATE_SECTION, POWER_STATE_SECTION_NAME);
×
1169
        break;
×
1170
      case ola::rdm::PID_RESET_DEVICE:
×
1171
        AddSection(&sections, RESET_DEVICE_SECTION, RESET_DEVICE_SECTION_NAME);
×
1172
        break;
×
1173
      case ola::rdm::PID_DNS_HOSTNAME:
×
1174
        AddSection(&sections, DNS_HOSTNAME_SECTION, DNS_HOSTNAME_SECTION_NAME);
×
1175
        break;
×
1176
      case ola::rdm::PID_DNS_DOMAIN_NAME:
×
1177
        AddSection(&sections,
×
1178
                   DNS_DOMAIN_NAME_SECTION,
1179
                   DNS_DOMAIN_NAME_SECTION_NAME);
1180
        break;
×
1181
      case ola::rdm::PID_CURVE:
×
1182
        AddSection(&sections, CURVE_SECTION, CURVE_SECTION_NAME);
×
1183
        break;
×
1184
      case ola::rdm::PID_DIMMER_INFO:
×
1185
        AddSection(&sections, DIMMER_INFO_SECTION, DIMMER_INFO_SECTION_NAME);
×
1186
        break;
×
1187
      case ola::rdm::PID_MINIMUM_LEVEL:
×
1188
        AddSection(&sections, DIMMER_MINIMUM_SECTION,
×
1189
                   DIMMER_MINIMUM_SECTION_NAME);
1190
        break;
×
1191
      case ola::rdm::PID_MAXIMUM_LEVEL:
×
1192
        AddSection(&sections, DIMMER_MAXIMUM_SECTION,
×
1193
                   DIMMER_MAXIMUM_SECTION_NAME);
1194
        break;
×
1195
    }
1196
  }
1197

1198
  if (include_software_version) {
×
1199
    AddSection(&sections, BOOT_SOFTWARE_SECTION, BOOT_SOFTWARE_SECTION_NAME);
×
1200
  }
1201

1202
  if (CheckForRDMSuccess(status)) {
×
1203
    if (device.dmx_footprint && !dmx_address_added) {
×
1204
      AddSection(&sections, DMX_ADDRESS_SECTION, DMX_ADDRESS_SECTION_NAME);
×
1205
    }
1206
    if (device.sensor_count &&
×
1207
        pids.find(ola::rdm::PID_SENSOR_DEFINITION) != pids.end() &&
×
1208
        pids.find(ola::rdm::PID_SENSOR_VALUE) != pids.end()) {
×
1209
      // sensors count from 1
1210
      for (unsigned int i = 0; i < device.sensor_count; ++i) {
×
1211
        ostringstream heading, hint;
×
1212
        hint << i;
×
1213
        heading << "Sensor " << std::setfill(' ') << std::setw(3) << i;
×
1214
        AddSection(&sections, SENSOR_SECTION, heading.str(), hint.str());
×
1215
      }
×
1216
    }
1217
  }
1218

1219
  sort(sections.begin(), sections.end(), lt_section_info());
×
1220

1221
  JsonArray json;
×
1222
  vector<section_info>::const_iterator section_iter = sections.begin();
×
1223
  for (; section_iter != sections.end(); ++section_iter) {
×
1224
    JsonObject *json_obj = json.AppendObject();
×
1225
    json_obj->Add("id", section_iter->id);
×
1226
    json_obj->Add("name", section_iter->name);
×
1227
    json_obj->Add("hint",  section_iter->hint);
×
1228
  }
1229

1230
  response->SetNoCache();
×
1231
  response->SetContentType(HTTPServer::CONTENT_TYPE_PLAIN);
×
1232
  response->SendJson(json);
×
1233
  delete response;
×
1234
}
×
1235

1236

1237
/*
1238
 * @brief Handle the request for the communication status.
1239
 */
1240
string RDMHTTPModule::GetCommStatus(HTTPResponse *response,
×
1241
                                    unsigned int universe_id,
1242
                                    const UID &uid) {
1243
  string error;
×
1244
  m_rdm_api.GetCommStatus(
×
1245
    universe_id,
1246
    uid,
1247
    NewSingleCallback(this,
1248
                      &RDMHTTPModule::CommStatusHandler,
1249
                      response),
1250
    &error);
1251
  return error;
×
1252
}
×
1253

1254

1255
/**
1256
 * @brief Handle the response to a communication status call
1257
 */
1258
void RDMHTTPModule::CommStatusHandler(HTTPResponse *response,
×
1259
                                      const ola::rdm::ResponseStatus &status,
1260
                                      uint16_t short_messages,
1261
                                      uint16_t length_mismatch,
1262
                                      uint16_t checksum_fail) {
1263
  if (CheckForRDMError(response, status)) {
×
1264
    return;
×
1265
  }
1266
  JsonSection section;
×
1267

1268
  section.AddItem(new UIntItem("Short Messages", short_messages));
×
1269
  section.AddItem(new UIntItem("Length Mismatch", length_mismatch));
×
1270
  section.AddItem(new UIntItem("Checksum Failures", checksum_fail));
×
1271
  section.AddItem(new HiddenItem("1", GENERIC_UINT_FIELD));
×
1272
  section.SetSaveButton("Clear Counters");
×
1273
  RespondWithSection(response, section);
×
1274
}
×
1275

1276

1277
/**
1278
 * @brief Clear the communication status counters
1279
 */
1280
string RDMHTTPModule::ClearCommsCounters(HTTPResponse *response,
×
1281
                                         unsigned int universe_id,
1282
                                         const UID &uid) {
1283
  string error;
×
1284
  m_rdm_api.ClearCommStatus(
×
1285
      universe_id,
1286
      uid,
1287
      NewSingleCallback(this,
1288
                        &RDMHTTPModule::SetHandler,
1289
                        response),
1290
      &error);
1291
  return error;
×
1292
}
×
1293

1294

1295
/*
1296
 * @brief Handle the request for the proxied devices
1297
 */
1298
string RDMHTTPModule::GetProxiedDevices(HTTPResponse *response,
×
1299
                                        unsigned int universe_id,
1300
                                        const UID &uid) {
1301
  string error;
×
1302
  m_rdm_api.GetProxiedDevices(
×
1303
    universe_id,
1304
    uid,
1305
    NewSingleCallback(this,
1306
                      &RDMHTTPModule::ProxiedDevicesHandler,
1307
                      response,
1308
                      universe_id),
1309
    &error);
1310
  return error;
×
1311
}
×
1312

1313

1314
/**
1315
 * @brief Handle the response to a proxied devices call.
1316
 */
1317
void RDMHTTPModule::ProxiedDevicesHandler(
×
1318
    HTTPResponse *response,
1319
    unsigned int universe_id,
1320
    const ola::rdm::ResponseStatus &status,
1321
    const vector<UID> &uids) {
1322
  if (CheckForRDMError(response, status)) {
×
1323
    return;
×
1324
  }
1325
  JsonSection section;
×
1326

1327
  uid_resolution_state *uid_state = GetUniverseUids(universe_id);
×
1328
  vector<UID>::const_iterator iter = uids.begin();
×
1329
  unsigned int i = 1;
×
1330
  for (; iter != uids.end(); ++iter, ++i) {
×
1331
    string uid = iter->ToString();
×
1332

1333
    // attempt to add device & manufacturer names
1334
    if (uid_state) {
×
1335
      map<UID, resolved_uid>::iterator uid_iter =
×
1336
        uid_state->resolved_uids.find(*iter);
×
1337

1338
      if (uid_iter != uid_state->resolved_uids.end()) {
×
1339
        string device = uid_iter->second.device;
×
1340
        string manufacturer = uid_iter->second.manufacturer;
×
1341

1342
        if (!(device.empty() && manufacturer.empty())) {
×
1343
          ostringstream str;
×
1344
          str << uid_iter->second.manufacturer;
×
1345
          if ((!device.empty()) && (!manufacturer.empty())) {
×
1346
            str << ", ";
×
1347
          }
1348
          str << uid_iter->second.device;
×
1349
          str << " [";
×
1350
          str << iter->ToString();
×
1351
          str << "]";
×
1352
          uid = str.str();
×
1353
        }
×
1354
      }
×
1355
    }
1356
    section.AddItem(new StringItem("Device " + IntToString(i), uid));
×
1357
  }
×
1358
  RespondWithSection(response, section);
×
1359
}
×
1360

1361

1362
/*
1363
 * @brief Handle the request for the device info section.
1364
 */
1365
string RDMHTTPModule::GetDeviceInfo(const HTTPRequest *request,
×
1366
                                    HTTPResponse *response,
1367
                                    unsigned int universe_id,
1368
                                    const UID &uid) {
1369
  string hint = request->GetParameter(HINT_KEY);
×
1370
  string error;
×
1371
  device_info dev_info = {universe_id, uid, hint, "", ""};
×
1372

1373
  m_rdm_api.GetSoftwareVersionLabel(
×
1374
    universe_id,
1375
    uid,
1376
    ola::rdm::ROOT_RDM_DEVICE,
1377
    NewSingleCallback(this,
×
1378
                      &RDMHTTPModule::GetSoftwareVersionHandler,
1379
                      response,
1380
                      dev_info),
1381
    &error);
1382
  return error;
×
1383
}
×
1384

1385

1386
/**
1387
 * @brief Handle the response to a software version call.
1388
 */
1389
void RDMHTTPModule::GetSoftwareVersionHandler(
×
1390
    HTTPResponse *response,
1391
    device_info dev_info,
1392
    const ola::rdm::ResponseStatus &status,
1393
    const string &software_version) {
1394
  string error;
×
1395

1396
  if (CheckForRDMSuccess(status)) {
×
1397
    dev_info.software_version = software_version;
×
1398
  }
1399

1400
  if (dev_info.hint.find('m') != string::npos) {
×
1401
    m_rdm_api.GetDeviceModelDescription(
×
1402
        dev_info.universe_id,
1403
        dev_info.uid,
×
1404
        ola::rdm::ROOT_RDM_DEVICE,
1405
        NewSingleCallback(this,
×
1406
                          &RDMHTTPModule::GetDeviceModelHandler,
1407
                          response,
1408
                          dev_info),
1409
        &error);
1410
  } else {
1411
    m_rdm_api.GetDeviceInfo(
×
1412
        dev_info.universe_id,
1413
        dev_info.uid,
×
1414
        ola::rdm::ROOT_RDM_DEVICE,
1415
        NewSingleCallback(this,
×
1416
                          &RDMHTTPModule::GetDeviceInfoHandler,
1417
                          response,
1418
                          dev_info),
1419
        &error);
1420
  }
1421

1422
  if (!error.empty()) {
×
1423
    m_server->ServeError(response, BACKEND_DISCONNECTED_ERROR + error);
×
1424
  }
1425
}
×
1426

1427

1428
/**
1429
 * @brief Handle the response to a device model call.
1430
 */
1431
void RDMHTTPModule::GetDeviceModelHandler(
×
1432
    HTTPResponse *response,
1433
    device_info dev_info,
1434
    const ola::rdm::ResponseStatus &status,
1435
    const string &device_model) {
1436
  string error;
×
1437

1438
  if (CheckForRDMSuccess(status)) {
×
1439
    dev_info.device_model = device_model;
×
1440
  }
1441

1442
  m_rdm_api.GetDeviceInfo(
×
1443
      dev_info.universe_id,
1444
      dev_info.uid,
×
1445
      ola::rdm::ROOT_RDM_DEVICE,
1446
      NewSingleCallback(this,
×
1447
                        &RDMHTTPModule::GetDeviceInfoHandler,
1448
                        response,
1449
                        dev_info),
1450
      &error);
1451

1452
  if (!error.empty()) {
×
1453
    m_server->ServeError(response, BACKEND_DISCONNECTED_ERROR + error);
×
1454
  }
1455
}
×
1456

1457

1458
/**
1459
 * @brief Handle the response to a device info call and build the response
1460
 */
1461
void RDMHTTPModule::GetDeviceInfoHandler(
×
1462
    HTTPResponse *response,
1463
    device_info dev_info,
1464
    const ola::rdm::ResponseStatus &status,
1465
    const ola::rdm::DeviceDescriptor &device) {
1466
  JsonSection section;
×
1467

1468
  if (CheckForRDMError(response, status)) {
×
1469
    return;
×
1470
  }
1471

1472
  ostringstream stream;
×
1473
  stream << static_cast<int>(device.protocol_version_high) << "."
×
1474
         << static_cast<int>(device.protocol_version_low);
×
1475
  section.AddItem(new StringItem("Protocol Version", stream.str()));
×
1476

1477
  stream.str("");
×
1478
  if (dev_info.device_model.empty()) {
×
1479
    stream << device.device_model;
×
1480
  } else {
1481
    stream << dev_info.device_model << " (" << device.device_model << ")";
×
1482
  }
1483
  section.AddItem(new StringItem("Device Model", stream.str()));
×
1484

1485
  section.AddItem(new StringItem(
×
1486
      "Product Category",
1487
      ola::rdm::ProductCategoryToString(device.product_category)));
×
1488
  stream.str("");
×
1489
  if (dev_info.software_version.empty()) {
×
1490
    stream << device.software_version;
×
1491
  } else {
1492
    stream << dev_info.software_version << " (" << device.software_version
×
1493
           << ")";
×
1494
  }
1495
  section.AddItem(new StringItem("Software Version", stream.str()));
×
1496

1497
  if (device.dmx_start_address == ola::rdm::ZERO_FOOTPRINT_DMX_ADDRESS) {
×
1498
    section.AddItem(new StringItem("DMX Address", "N/A"));
×
1499
  } else {
1500
    section.AddItem(new UIntItem("DMX Address", device.dmx_start_address));
×
1501
  }
1502

1503
  section.AddItem(new UIntItem("DMX Footprint", device.dmx_footprint));
×
1504

1505
  stream.str("");
×
1506
  stream << static_cast<int>(device.current_personality) << " of "
×
1507
         << static_cast<int>(device.personality_count);
×
1508
  section.AddItem(new StringItem("Personality", stream.str()));
×
1509

1510
  section.AddItem(new UIntItem("Sub Devices", device.sub_device_count));
×
1511
  section.AddItem(new UIntItem("Sensors", device.sensor_count));
×
1512
  section.AddItem(new StringItem("UID", dev_info.uid.ToString()));
×
1513
  RespondWithSection(response, section);
×
1514
}
×
1515

1516

1517
/*
1518
 * @brief Handle the request for the product details ids.
1519
 */
1520
string RDMHTTPModule::GetProductIds(OLA_UNUSED const HTTPRequest *request,
×
1521
                                    HTTPResponse *response,
1522
                                    unsigned int universe_id,
1523
                                    const UID &uid) {
1524
  string error;
×
1525
  m_rdm_api.GetProductDetailIdList(
×
1526
      universe_id,
1527
      uid,
1528
      ola::rdm::ROOT_RDM_DEVICE,
1529
      NewSingleCallback(this,
1530
                        &RDMHTTPModule::GetProductIdsHandler,
1531
                        response),
1532
      &error);
1533
  return error;
×
1534
}
×
1535

1536

1537
/**
1538
 * @brief Handle the response to a product detail ids call and build the response.
1539
 */
1540
void RDMHTTPModule::GetProductIdsHandler(
×
1541
    HTTPResponse *response,
1542
    const ola::rdm::ResponseStatus &status,
1543
    const vector<uint16_t> &ids) {
1544
  if (CheckForRDMError(response, status)) {
×
1545
    return;
×
1546
  }
1547

1548
  bool first = true;
×
1549
  ostringstream product_ids;
×
1550
  JsonSection section;
×
1551
  vector<uint16_t>::const_iterator iter = ids.begin();
×
1552
  for (; iter != ids.end(); ++iter) {
×
1553
    string product_id = ola::rdm::ProductDetailToString(*iter);
×
1554
    if (product_id.empty()) {
×
1555
      continue;
×
1556
    }
1557

1558
    if (first) {
×
1559
      first = false;
1560
    } else {
1561
      product_ids << ", ";
×
1562
    }
1563
    product_ids << product_id;
×
1564
  }
×
1565
  section.AddItem(new StringItem("Product Detail IDs", product_ids.str()));
×
1566
  RespondWithSection(response, section);
×
1567
}
×
1568

1569

1570
/**
1571
 * @brief Handle the request for the Manufacturer label.
1572
 */
1573
string RDMHTTPModule::GetManufacturerLabel(
×
1574
    OLA_UNUSED const HTTPRequest *request,
1575
    HTTPResponse *response,
1576
    unsigned int universe_id,
1577
    const UID &uid) {
1578
  string error;
×
1579
  m_rdm_api.GetManufacturerLabel(
×
1580
      universe_id,
1581
      uid,
1582
      ola::rdm::ROOT_RDM_DEVICE,
1583
      NewSingleCallback(this,
×
1584
                        &RDMHTTPModule::GetManufacturerLabelHandler,
1585
                        response,
1586
                        universe_id,
1587
                        uid),
1588
      &error);
1589
  return error;
×
1590
}
×
1591

1592

1593
/**
1594
 * @brief Handle the response to a manufacturer label call and build the response
1595
 */
1596
void RDMHTTPModule::GetManufacturerLabelHandler(
×
1597
    HTTPResponse *response,
1598
    unsigned int universe_id,
1599
    const UID uid,
1600
    const ola::rdm::ResponseStatus &status,
1601
    const string &label) {
1602
  if (CheckForRDMError(response, status)) {
×
1603
    return;
×
1604
  }
1605
  JsonSection section;
×
1606
  section.AddItem(new StringItem("Manufacturer Label", label));
×
1607
  RespondWithSection(response, section);
×
1608

1609
  // update the map as well
1610
  uid_resolution_state *uid_state = GetUniverseUids(universe_id);
×
1611
  if (uid_state) {
×
1612
    map<UID, resolved_uid>::iterator uid_iter =
×
1613
      uid_state->resolved_uids.find(uid);
×
1614
    if (uid_iter != uid_state->resolved_uids.end()) {
×
1615
      uid_iter->second.manufacturer = label;
×
1616
    }
1617
  }
1618
}
×
1619

1620

1621
/**
1622
 * @brief Handle the request for the Device label.
1623
 */
1624
string RDMHTTPModule::GetDeviceLabel(OLA_UNUSED const HTTPRequest *request,
×
1625
                                     HTTPResponse *response,
1626
                                     unsigned int universe_id,
1627
                                     const UID &uid) {
1628
  string error;
×
1629
  m_rdm_api.GetDeviceLabel(
×
1630
      universe_id,
1631
      uid,
1632
      ola::rdm::ROOT_RDM_DEVICE,
1633
      NewSingleCallback(this,
×
1634
                        &RDMHTTPModule::GetDeviceLabelHandler,
1635
                        response,
1636
                        universe_id,
1637
                        uid),
1638
      &error);
1639
  return error;
×
1640
}
×
1641

1642

1643
/**
1644
 * @brief Handle the response to a device label call and build the response
1645
 */
1646
void RDMHTTPModule::GetDeviceLabelHandler(
×
1647
    HTTPResponse *response,
1648
    unsigned int universe_id,
1649
    const UID uid,
1650
    const ola::rdm::ResponseStatus &status,
1651
    const string &label) {
1652
  if (CheckForRDMError(response, status)) {
×
1653
    return;
×
1654
  }
1655

1656
  JsonSection section;
×
1657
  section.AddItem(new StringItem("Device Label", label, LABEL_FIELD));
×
1658
  RespondWithSection(response, section);
×
1659

1660
  // update the map as well
1661
  uid_resolution_state *uid_state = GetUniverseUids(universe_id);
×
1662
  if (uid_state) {
×
1663
    map<UID, resolved_uid>::iterator uid_iter =
×
1664
      uid_state->resolved_uids.find(uid);
×
1665
    if (uid_iter != uid_state->resolved_uids.end()) {
×
1666
      uid_iter->second.device = label;
×
1667
    }
1668
  }
1669
}
×
1670

1671

1672
/*
1673
 * @brief Set the device label
1674
 */
1675
string RDMHTTPModule::SetDeviceLabel(const HTTPRequest *request,
×
1676
                                     HTTPResponse *response,
1677
                                     unsigned int universe_id,
1678
                                     const UID &uid) {
1679
  string label = request->GetParameter(LABEL_FIELD);
×
1680
  string error;
×
1681
  m_rdm_api.SetDeviceLabel(
×
1682
      universe_id,
1683
      uid,
1684
      ola::rdm::ROOT_RDM_DEVICE,
1685
      label,
1686
      NewSingleCallback(this,
1687
                        &RDMHTTPModule::SetHandler,
1688
                        response),
1689
      &error);
1690
  return error;
×
1691
}
×
1692

1693

1694
/**
1695
 * @brief Handle the request for the factory defaults section
1696
 */
1697
string RDMHTTPModule::GetFactoryDefaults(HTTPResponse *response,
×
1698
                                         unsigned int universe_id,
1699
                                         const UID &uid) {
1700
  string error;
×
1701
  m_rdm_api.GetFactoryDefaults(
×
1702
      universe_id,
1703
      uid,
1704
      ola::rdm::ROOT_RDM_DEVICE,
1705
      NewSingleCallback(this,
1706
                        &RDMHTTPModule::FactoryDefaultsHandler,
1707
                        response),
1708
      &error);
1709
  return error;
×
1710
}
×
1711

1712

1713
/**
1714
 * @brief Handle the response to a factory defaults call and build the response
1715
 */
1716
void RDMHTTPModule::FactoryDefaultsHandler(
×
1717
    HTTPResponse *response,
1718
    const ola::rdm::ResponseStatus &status,
1719
    bool defaults) {
1720
  if (CheckForRDMError(response, status)) {
×
1721
    return;
×
1722
  }
1723

1724
  JsonSection section;
×
1725
  section.AddItem(new StringItem("Using Defaults",
×
1726
                                 defaults ? "Yes" : "No"));
×
1727
  section.AddItem(new HiddenItem("1", GENERIC_UINT_FIELD));
×
1728
  section.SetSaveButton("Reset to Defaults");
×
1729
  RespondWithSection(response, section);
×
1730
}
×
1731

1732

1733
/*
1734
 * @brief Reset to the factory defaults
1735
 */
1736
string RDMHTTPModule::SetFactoryDefault(HTTPResponse *response,
×
1737
                                        unsigned int universe_id,
1738
                                        const UID &uid) {
1739
  string error;
×
1740
  m_rdm_api.ResetToFactoryDefaults(
×
1741
      universe_id,
1742
      uid,
1743
      ola::rdm::ROOT_RDM_DEVICE,
1744
      NewSingleCallback(this,
1745
                        &RDMHTTPModule::SetHandler,
1746
                        response),
1747
      &error);
1748
  return error;
×
1749
}
×
1750

1751

1752
/**
1753
 * @brief Handle the request for the language section.
1754
 */
1755
string RDMHTTPModule::GetLanguage(HTTPResponse *response,
×
1756
                                  unsigned int universe_id,
1757
                                  const UID &uid) {
1758
  string error;
×
1759
  m_rdm_api.GetLanguageCapabilities(
×
1760
      universe_id,
1761
      uid,
1762
      ola::rdm::ROOT_RDM_DEVICE,
1763
      NewSingleCallback(this,
×
1764
                        &RDMHTTPModule::GetSupportedLanguagesHandler,
1765
                        response,
1766
                        universe_id,
1767
                        uid),
1768
      &error);
1769
  return error;
×
1770
}
×
1771

1772

1773
/**
1774
 * @brief Handle the response to language capability call.
1775
 */
1776
void RDMHTTPModule::GetSupportedLanguagesHandler(
×
1777
    HTTPResponse *response,
1778
    unsigned int universe_id,
1779
    const UID uid,
1780
    OLA_UNUSED const ola::rdm::ResponseStatus &status,
1781
    const vector<string> &languages) {
1782
  string error;
×
1783
  m_rdm_api.GetLanguage(
×
1784
      universe_id,
1785
      uid,
1786
      ola::rdm::ROOT_RDM_DEVICE,
1787
      NewSingleCallback(this,
×
1788
                        &RDMHTTPModule::GetLanguageHandler,
1789
                        response,
1790
                        languages),
1791
      &error);
1792

1793
  if (!error.empty()) {
×
1794
    m_server->ServeError(response, BACKEND_DISCONNECTED_ERROR + error);
×
1795
  }
1796
}
×
1797

1798

1799
/**
1800
 * @brief Handle the response to language call and build the response
1801
 */
1802
void RDMHTTPModule::GetLanguageHandler(HTTPResponse *response,
×
1803
                                       vector<string> languages,
1804
                                       const ola::rdm::ResponseStatus &status,
1805
                                       const string &language) {
1806
  JsonSection section;
×
1807
  SelectItem *item = new SelectItem("Language", LANGUAGE_FIELD);
×
1808
  bool ok = CheckForRDMSuccess(status);
×
1809

1810
  vector<string>::const_iterator iter = languages.begin();
×
1811
  unsigned int i = 0;
×
1812
  for (; iter != languages.end(); ++iter, i++) {
×
1813
    item->AddItem(*iter, *iter);
×
1814
    if (ok && *iter == language) {
×
1815
      item->SetSelectedOffset(i);
×
1816
    }
1817
  }
1818

1819
  if (ok && languages.empty()) {
×
1820
    item->AddItem(language, language);
×
1821
    item->SetSelectedOffset(0);
×
1822
  }
1823
  section.AddItem(item);
×
1824
  RespondWithSection(response, section);
×
1825
}
×
1826

1827

1828
/*
1829
 * @brief Set the language
1830
 */
1831
string RDMHTTPModule::SetLanguage(const HTTPRequest *request,
×
1832
                                  HTTPResponse *response,
1833
                                  unsigned int universe_id,
1834
                                  const UID &uid) {
1835
  string label = request->GetParameter(LANGUAGE_FIELD);
×
1836
  string error;
×
1837
  m_rdm_api.SetLanguage(
×
1838
      universe_id,
1839
      uid,
1840
      ola::rdm::ROOT_RDM_DEVICE,
1841
      label,
1842
      NewSingleCallback(this,
1843
                        &RDMHTTPModule::SetHandler,
1844
                        response),
1845
      &error);
1846
  return error;
×
1847
}
×
1848

1849

1850
/**
1851
 * @brief Handle the request for the boot software section.
1852
 */
1853
string RDMHTTPModule::GetBootSoftware(HTTPResponse *response,
×
1854
                                      unsigned int universe_id,
1855
                                      const UID &uid) {
1856
  string error;
×
1857
  m_rdm_api.GetBootSoftwareVersionLabel(
×
1858
      universe_id,
1859
      uid,
1860
      ola::rdm::ROOT_RDM_DEVICE,
1861
      NewSingleCallback(this,
×
1862
                        &RDMHTTPModule::GetBootSoftwareLabelHandler,
1863
                        response,
1864
                        universe_id,
1865
                        uid),
1866
      &error);
1867
  return error;
×
1868
}
×
1869

1870

1871
/**
1872
 * @brief Handle the response to a boot software label.
1873
 */
1874
void RDMHTTPModule::GetBootSoftwareLabelHandler(
×
1875
    HTTPResponse *response,
1876
    unsigned int universe_id,
1877
    const UID uid,
1878
    OLA_UNUSED const ola::rdm::ResponseStatus &status,
1879
    const string &label) {
1880
  string error;
×
1881
  m_rdm_api.GetBootSoftwareVersion(
×
1882
      universe_id,
1883
      uid,
1884
      ola::rdm::ROOT_RDM_DEVICE,
1885
      NewSingleCallback(this,
×
1886
                        &RDMHTTPModule::GetBootSoftwareVersionHandler,
1887
                        response,
1888
                        label),
1889
      &error);
1890
  if (!error.empty()) {
×
1891
    m_server->ServeError(response, BACKEND_DISCONNECTED_ERROR + error);
×
1892
  }
1893
}
×
1894

1895

1896
/**
1897
 * @brief Handle the response to a boot software version.
1898
 */
1899
void RDMHTTPModule::GetBootSoftwareVersionHandler(
×
1900
    HTTPResponse *response,
1901
    string label,
1902
    const ola::rdm::ResponseStatus &status,
1903
    uint32_t version) {
1904
  ostringstream str;
×
1905
  str << label;
×
1906
  if (CheckForRDMSuccess(status)) {
×
1907
    if (!label.empty()) {
×
1908
      str << " (" << version << ")";
×
1909
    } else {
1910
      str << version;
×
1911
    }
1912
  }
1913

1914
  JsonSection section;
×
1915
  StringItem *item = new StringItem("Boot Software", str.str());
×
1916
  section.AddItem(item);
×
1917
  RespondWithSection(response, section);
×
1918
}
×
1919

1920

1921
/**
1922
 * @brief Handle the request for the personality section.
1923
 */
1924
string RDMHTTPModule::GetPersonalities(OLA_UNUSED const HTTPRequest *request,
×
1925
                                       HTTPResponse *response,
1926
                                       unsigned int universe_id,
1927
                                       const UID &uid,
1928
                                       bool return_as_section,
1929
                                       bool include_descriptions) {
1930
  string hint = request->GetParameter(HINT_KEY);
×
1931
  string error;
×
1932

1933
  personality_info *info = new personality_info;
×
1934
  info->universe_id = universe_id;
×
1935
  info->uid = new UID(uid);
×
1936
  info->include_descriptions = include_descriptions || (hint == "l");
×
1937
  info->return_as_section = return_as_section;
×
1938
  info->active = 0;
×
1939
  info->next = 1;
×
1940
  info->total = 0;
×
1941

1942
  m_rdm_api.GetDMXPersonality(
×
1943
      universe_id,
1944
      uid,
1945
      ola::rdm::ROOT_RDM_DEVICE,
1946
      NewSingleCallback(this,
1947
                        &RDMHTTPModule::GetPersonalityHandler,
1948
                        response,
1949
                        info),
1950
      &error);
1951
  return error;
×
1952
}
×
1953

1954

1955
/**
1956
 * @brief Handle the response to a dmx personality call.
1957
 */
1958
void RDMHTTPModule::GetPersonalityHandler(
×
1959
    HTTPResponse *response,
1960
    personality_info *info,
1961
    const ola::rdm::ResponseStatus &status,
1962
    uint8_t current,
1963
    uint8_t total) {
1964
  if (CheckForRDMError(response, status)) {
×
1965
    delete info->uid;
×
1966
    delete info;
×
1967
    return;
×
1968
  }
1969

1970
  info->active = current;
×
1971
  info->total = total;
×
1972

1973
  if (info->include_descriptions) {
×
1974
    GetNextPersonalityDescription(response, info);
×
1975
  } else {
1976
    SendPersonalityResponse(response, info);
×
1977
  }
1978
}
1979

1980

1981
/**
1982
 * @brief Get the description of the next dmx personality
1983
 */
1984
void RDMHTTPModule::GetNextPersonalityDescription(HTTPResponse *response,
×
1985
                                                  personality_info *info) {
1986
  string error;
×
1987
  while (info->next <= info->total) {
×
1988
    bool r = m_rdm_api.GetDMXPersonalityDescription(
×
1989
        info->universe_id,
1990
        *(info->uid),
×
1991
        ola::rdm::ROOT_RDM_DEVICE,
1992
        info->next,
×
1993
        NewSingleCallback(this,
1994
                          &RDMHTTPModule::GetPersonalityLabelHandler,
1995
                          response,
1996
                          info),
1997
        &error);
1998
    if (r) {
×
1999
      return;
×
2000
    }
2001

2002
    info->next++;
×
2003
  }
2004
  if (info->return_as_section) {
×
2005
    SendSectionPersonalityResponse(response, info);
×
2006
  } else {
2007
    SendPersonalityResponse(response, info);
×
2008
  }
2009
}
×
2010

2011

2012
/**
2013
 * @brief Handle the response to a Personality label call.
2014
 *
2015
 * This fetches the next personality in the sequence, or sends the response if
2016
 * we have all the info.
2017
 */
2018
void RDMHTTPModule::GetPersonalityLabelHandler(
×
2019
    HTTPResponse *response,
2020
    personality_info *info,
2021
    const ola::rdm::ResponseStatus &status,
2022
    OLA_UNUSED uint8_t personality,
2023
    uint16_t slot_count,
2024
    const string &label) {
2025
  string description = "";
×
2026
  uint32_t slots = INVALID_PERSONALITY;
×
2027

2028
  if (CheckForRDMSuccess(status)) {
×
2029
    slots = slot_count;
×
2030
    description = label;
×
2031
  }
2032

2033
  info->personalities.push_back(pair<uint32_t, string>(slots, description));
×
2034

2035
  if (info->next == info->total) {
×
2036
    if (info->return_as_section) {
×
2037
      SendSectionPersonalityResponse(response, info);
×
2038
    } else {
2039
      SendPersonalityResponse(response, info);
×
2040
    }
2041
  } else {
2042
    info->next++;
×
2043
    GetNextPersonalityDescription(response, info);
×
2044
  }
2045
}
×
2046

2047

2048
/**
2049
 * @brief Send the response to a dmx personality section
2050
 */
2051
void RDMHTTPModule::SendSectionPersonalityResponse(HTTPResponse *response,
×
2052
                                                   personality_info *info) {
2053
  JsonSection section;
×
2054
  SelectItem *item = new SelectItem("Personality", GENERIC_UINT_FIELD);
×
2055

2056
  for (unsigned int i = 1; i <= info->total; i++) {
×
2057
    if (i <= info->personalities.size() &&
×
2058
        info->personalities[i - 1].first != INVALID_PERSONALITY) {
×
2059
      ostringstream str;
×
2060
      str << info->personalities[i - 1].second << " (" <<
×
2061
        info->personalities[i - 1].first << ")";
×
2062
      item->AddItem(str.str(), i);
×
2063
    } else {
×
2064
      item->AddItem(IntToString(i), i);
×
2065
    }
2066

2067
    if (info->active == i) {
×
2068
      item->SetSelectedOffset(i - 1);
×
2069
    }
2070
  }
2071
  section.AddItem(item);
×
2072
  RespondWithSection(response, section);
×
2073

2074
  delete info->uid;
×
2075
  delete info;
×
2076
}
×
2077

2078

2079
/**
2080
 * @brief Set the personality
2081
 */
2082
string RDMHTTPModule::SetPersonality(const HTTPRequest *request,
×
2083
                                     HTTPResponse *response,
2084
                                     unsigned int universe_id,
2085
                                     const UID &uid) {
2086
  string personality_str = request->GetParameter(GENERIC_UINT_FIELD);
×
2087
  uint8_t personality;
×
2088

2089
  if (!StringToInt(personality_str, &personality)) {
×
2090
    return "Invalid personality";
×
2091
  }
2092

2093
  string error;
×
2094
  m_rdm_api.SetDMXPersonality(
×
2095
      universe_id,
2096
      uid,
2097
      ola::rdm::ROOT_RDM_DEVICE,
2098
      personality,
2099
      NewSingleCallback(this,
2100
                        &RDMHTTPModule::SetHandler,
2101
                        response),
2102
      &error);
2103
  return error;
×
2104
}
×
2105

2106

2107
/**
2108
 * @brief Handle the request for the start address section.
2109
 */
2110
string RDMHTTPModule::GetStartAddress(OLA_UNUSED const HTTPRequest *request,
×
2111
                                      HTTPResponse *response,
2112
                                      unsigned int universe_id,
2113
                                      const UID &uid) {
2114
  string error;
×
2115
  m_rdm_api.GetDMXAddress(
×
2116
      universe_id,
2117
      uid,
2118
      ola::rdm::ROOT_RDM_DEVICE,
2119
      NewSingleCallback(this,
2120
                        &RDMHTTPModule::GetStartAddressHandler,
2121
                        response),
2122
      &error);
2123
  return error;
×
2124
}
×
2125

2126

2127
/**
2128
 * @brief Handle the response to a dmx start address call and build the response
2129
 */
2130
void RDMHTTPModule::GetStartAddressHandler(
×
2131
    HTTPResponse *response,
2132
    const ola::rdm::ResponseStatus &status,
2133
    uint16_t address) {
2134
  if (CheckForRDMError(response, status)) {
×
2135
    return;
×
2136
  }
2137

2138
  JsonSection section;
×
2139
  GenericItem *item = NULL;
×
2140
  if (address == ola::rdm::ZERO_FOOTPRINT_DMX_ADDRESS) {
×
2141
    item = new StringItem("DMX Start Address", "N/A");
×
2142
  } else {
2143
    UIntItem *uint_item = new UIntItem("DMX Start Address", address,
×
2144
                                       ADDRESS_FIELD);
×
2145
    uint_item->SetMin(DMX_MIN_SLOT_NUMBER);
×
2146
    uint_item->SetMax(DMX_MAX_SLOT_NUMBER);
×
2147
    item = uint_item;
×
2148
  }
2149
  section.AddItem(item);
×
2150
  RespondWithSection(response, section);
×
2151
}
×
2152

2153

2154
/*
2155
 * @brief Set the DMX start address
2156
 */
2157
string RDMHTTPModule::SetStartAddress(const HTTPRequest *request,
×
2158
                                      HTTPResponse *response,
2159
                                      unsigned int universe_id,
2160
                                      const UID &uid) {
2161
  string dmx_address = request->GetParameter(ADDRESS_FIELD);
×
2162
  uint16_t address;
×
2163

2164
  if (!StringToInt(dmx_address, &address)) {
×
2165
    return "Invalid start address";
×
2166
  }
2167

2168
  string error;
×
2169
  m_rdm_api.SetDMXAddress(
×
2170
      universe_id,
2171
      uid,
2172
      ola::rdm::ROOT_RDM_DEVICE,
2173
      address,
2174
      NewSingleCallback(this,
2175
                        &RDMHTTPModule::SetHandler,
2176
                        response),
2177
      &error);
2178
  return error;
×
2179
}
×
2180

2181

2182
/**
2183
 * @brief Handle the request for the sensor section.
2184
 */
2185
string RDMHTTPModule::GetSensor(const HTTPRequest *request,
×
2186
                                HTTPResponse *response,
2187
                                unsigned int universe_id,
2188
                                const UID &uid) {
2189
  string hint = request->GetParameter(HINT_KEY);
×
2190
  uint8_t sensor_id;
×
2191
  if (!StringToInt(hint, &sensor_id)) {
×
2192
    return "Invalid hint (sensor #)";
×
2193
  }
2194

2195
  string error;
×
2196
  m_rdm_api.GetSensorDefinition(
×
2197
      universe_id,
2198
      uid,
2199
      ola::rdm::ROOT_RDM_DEVICE,
2200
      sensor_id,
2201
      NewSingleCallback(this,
×
2202
                        &RDMHTTPModule::SensorDefinitionHandler,
2203
                        response,
2204
                        universe_id,
2205
                        uid,
2206
                        sensor_id),
2207
      &error);
2208
  return error;
×
2209
}
×
2210

2211

2212
/**
2213
 * @brief Handle the response to a sensor definition request.
2214
 */
2215
void RDMHTTPModule::SensorDefinitionHandler(
×
2216
    HTTPResponse *response,
2217
    unsigned int universe_id,
2218
    const UID uid,
2219
    uint8_t sensor_id,
2220
    const ola::rdm::ResponseStatus &status,
2221
    const ola::rdm::SensorDescriptor &definition) {
2222
  ola::rdm::SensorDescriptor *definition_arg = NULL;
×
2223

2224
  if (CheckForRDMSuccess(status)) {
×
2225
    definition_arg = new ola::rdm::SensorDescriptor();
×
2226
    *definition_arg = definition;
×
2227
  }
2228
  string error;
×
2229
  m_rdm_api.GetSensorValue(
×
2230
      universe_id,
2231
      uid,
2232
      ola::rdm::ROOT_RDM_DEVICE,
2233
      sensor_id,
2234
      NewSingleCallback(this,
2235
                        &RDMHTTPModule::SensorValueHandler,
2236
                        response,
2237
                        definition_arg),
2238
      &error);
2239
  if (!error.empty()) {
×
2240
    m_server->ServeError(response, BACKEND_DISCONNECTED_ERROR + error);
×
2241
  }
2242
}
×
2243

2244

2245
/**
2246
 * @brief Handle the response to a sensor value request & build the response.
2247
 */
2248
void RDMHTTPModule::SensorValueHandler(
×
2249
    HTTPResponse *response,
2250
    ola::rdm::SensorDescriptor *definition,
2251
    const ola::rdm::ResponseStatus &status,
2252
    const ola::rdm::SensorValueDescriptor &value) {
2253
  if (CheckForRDMError(response, status)) {
×
2254
    if (definition) {
×
2255
      delete definition;
×
2256
    }
2257
    return;
×
2258
  }
2259

2260
  JsonSection section;
×
2261
  ostringstream str;
×
2262

2263
  if (definition) {
×
2264
    section.AddItem(new StringItem("Description", definition->description));
×
2265
  }
2266

2267
  str << value.present_value;
×
2268
  if (definition) {
×
2269
    str << " " << ola::rdm::PrefixToString(definition->prefix) << " "
×
2270
        << ola::rdm::UnitToString(definition->unit);
×
2271
  }
2272
  section.AddItem(new StringItem("Present Value", str.str()));
×
2273

2274
  if (definition) {
×
2275
    section.AddItem(new StringItem(
×
2276
          "Type",
2277
          ola::rdm::SensorTypeToString(definition->type)));
×
2278
    str.str("");
×
2279
    str << definition->range_min << " - " << definition->range_max << " "
×
2280
        << ola::rdm::PrefixToString(definition->prefix) << " " <<
×
2281
      ola::rdm::UnitToString(definition->unit);
×
2282
    section.AddItem(new StringItem("Range", str.str()));
×
2283

2284
    str.str("");
×
2285
    str << definition->normal_min << " - " << definition->normal_max << " "
×
2286
        << ola::rdm::PrefixToString(definition->prefix) << " " <<
×
2287
      ola::rdm::UnitToString(definition->unit);
×
2288
    section.AddItem(new StringItem("Normal Range", str.str()));
×
2289

2290
    if (definition->recorded_value_support &
×
2291
        ola::rdm::SENSOR_RECORDED_VALUE) {
2292
      str.str("");
×
2293
      str << value.recorded << " "
×
2294
          << ola::rdm::PrefixToString(definition->prefix) << " "
×
2295
          << ola::rdm::UnitToString(definition->unit);
×
2296
      section.AddItem(new StringItem("Recorded Value", str.str()));
×
2297
    }
2298

2299
    if (definition->recorded_value_support &
×
2300
        ola::rdm::SENSOR_RECORDED_RANGE_VALUES) {
2301
      str.str("");
×
2302
      str << value.lowest << " - " << value.highest << " "
×
2303
          << ola::rdm::PrefixToString(definition->prefix) << " "
×
2304
          << ola::rdm::UnitToString(definition->unit);
×
2305
      section.AddItem(new StringItem("Min / Max Recorded Values", str.str()));
×
2306
    }
2307
  }
2308

2309
  if (definition && definition->recorded_value_support) {
×
2310
    section.AddItem(new HiddenItem("1", RECORD_SENSOR_FIELD));
×
2311
  }
2312
  section.SetSaveButton("Record Sensor");
×
2313
  RespondWithSection(response, section);
×
2314
  delete definition;
×
2315
}
×
2316

2317

2318
/*
2319
 * @brief Record a sensor value
2320
 */
2321
string RDMHTTPModule::RecordSensor(const HTTPRequest *request,
×
2322
                                   HTTPResponse *response,
2323
                                   unsigned int universe_id,
2324
                                   const UID &uid) {
2325
  string hint = request->GetParameter(HINT_KEY);
×
2326
  uint8_t sensor_id;
×
2327
  if (!StringToInt(hint, &sensor_id)) {
×
2328
    return "Invalid hint (sensor #)";
×
2329
  }
2330

2331
  string error;
×
2332
  m_rdm_api.RecordSensors(
×
2333
      universe_id,
2334
      uid,
2335
      ola::rdm::ROOT_RDM_DEVICE,
2336
      sensor_id,
2337
      NewSingleCallback(this,
2338
                        &RDMHTTPModule::SetHandler,
2339
                        response),
2340
      &error);
2341
  return error;
×
2342
}
×
2343

2344

2345
/**
2346
 * @brief Handle the request for the device hours section.
2347
 */
2348
string RDMHTTPModule::GetDeviceHours(OLA_UNUSED const HTTPRequest *request,
×
2349
                                     HTTPResponse *response,
2350
                                     unsigned int universe_id,
2351
                                     const UID &uid) {
2352
  string error;
×
2353
  m_rdm_api.GetDeviceHours(
×
2354
      universe_id,
2355
      uid,
2356
      ola::rdm::ROOT_RDM_DEVICE,
2357
      NewSingleCallback(this,
2358
                        &RDMHTTPModule::GenericUIntHandler,
2359
                        response,
2360
                        string("Device Hours")),
×
2361
      &error);
2362
  return error;
×
2363
}
×
2364

2365

2366
/**
2367
 * @brief Set the device hours
2368
 */
2369
string RDMHTTPModule::SetDeviceHours(const HTTPRequest *request,
×
2370
                                     HTTPResponse *response,
2371
                                     unsigned int universe_id,
2372
                                     const UID &uid) {
2373
  string device_hours = request->GetParameter(GENERIC_UINT_FIELD);
×
2374
  uint32_t dev_hours;
×
2375

2376
  if (!StringToInt(device_hours, &dev_hours)) {
×
2377
    return "Invalid device hours";
×
2378
  }
2379

2380
  string error;
×
2381
  m_rdm_api.SetDeviceHours(
×
2382
      universe_id,
2383
      uid,
2384
      ola::rdm::ROOT_RDM_DEVICE,
2385
      dev_hours,
2386
      NewSingleCallback(this,
2387
                        &RDMHTTPModule::SetHandler,
2388
                        response),
2389
      &error);
2390
  return error;
×
2391
}
×
2392

2393

2394
/**
2395
 * @brief Handle the request for the lamp hours section.
2396
 */
2397
string RDMHTTPModule::GetLampHours(OLA_UNUSED const HTTPRequest *request,
×
2398
                                   HTTPResponse *response,
2399
                                   unsigned int universe_id,
2400
                                   const UID &uid) {
2401
  string error;
×
2402
  m_rdm_api.GetLampHours(
×
2403
      universe_id,
2404
      uid,
2405
      ola::rdm::ROOT_RDM_DEVICE,
2406
      NewSingleCallback(this,
2407
                        &RDMHTTPModule::GenericUIntHandler,
2408
                        response,
2409
                        string("Lamp Hours")),
×
2410
      &error);
2411
  return error;
×
2412
}
×
2413

2414

2415
/**
2416
 * @brief Set the lamp hours
2417
 */
2418
string RDMHTTPModule::SetLampHours(const HTTPRequest *request,
×
2419
                                   HTTPResponse *response,
2420
                                   unsigned int universe_id,
2421
                                   const UID &uid) {
2422
  string lamp_hours_str = request->GetParameter(GENERIC_UINT_FIELD);
×
2423
  uint32_t lamp_hours;
×
2424

2425
  if (!StringToInt(lamp_hours_str, &lamp_hours)) {
×
2426
    return "Invalid lamp hours";
×
2427
  }
2428

2429
  string error;
×
2430
  m_rdm_api.SetLampHours(
×
2431
      universe_id,
2432
      uid,
2433
      ola::rdm::ROOT_RDM_DEVICE,
2434
      lamp_hours,
2435
      NewSingleCallback(this,
2436
                        &RDMHTTPModule::SetHandler,
2437
                        response),
2438
      &error);
2439
  return error;
×
2440
}
×
2441

2442

2443
/**
2444
 * @brief Handle the request for the lamp strikes section
2445
 */
2446
string RDMHTTPModule::GetLampStrikes(OLA_UNUSED const HTTPRequest *request,
×
2447
                                     HTTPResponse *response,
2448
                                     unsigned int universe_id,
2449
                                     const UID &uid) {
2450
  string error;
×
2451
  m_rdm_api.GetLampStrikes(
×
2452
      universe_id,
2453
      uid,
2454
      ola::rdm::ROOT_RDM_DEVICE,
2455
      NewSingleCallback(this,
2456
                        &RDMHTTPModule::GenericUIntHandler,
2457
                        response,
2458
                        string("Lamp Strikes")),
×
2459
      &error);
2460
  return error;
×
2461
}
×
2462

2463

2464
/**
2465
 * @brief Set the lamp strikes
2466
 */
2467
string RDMHTTPModule::SetLampStrikes(const HTTPRequest *request,
×
2468
                                     HTTPResponse *response,
2469
                                     unsigned int universe_id,
2470
                                     const UID &uid) {
2471
  string lamp_strikes_str = request->GetParameter(GENERIC_UINT_FIELD);
×
2472
  uint32_t lamp_strikes;
×
2473

2474
  if (!StringToInt(lamp_strikes_str, &lamp_strikes)) {
×
2475
    return "Invalid lamp strikes";
×
2476
  }
2477

2478
  string error;
×
2479
  m_rdm_api.SetLampStrikes(
×
2480
      universe_id,
2481
      uid,
2482
      ola::rdm::ROOT_RDM_DEVICE,
2483
      lamp_strikes,
2484
      NewSingleCallback(this,
2485
                        &RDMHTTPModule::SetHandler,
2486
                        response),
2487
      &error);
2488
  return error;
×
2489
}
×
2490

2491

2492
/**
2493
 * @brief Handle the request for the lamp state section
2494
 */
2495
string RDMHTTPModule::GetLampState(OLA_UNUSED const HTTPRequest *request,
×
2496
                                   HTTPResponse *response,
2497
                                   unsigned int universe_id,
2498
                                   const UID &uid) {
2499
  string error;
×
2500
  m_rdm_api.GetLampState(
×
2501
      universe_id,
2502
      uid,
2503
      ola::rdm::ROOT_RDM_DEVICE,
2504
      NewSingleCallback(this,
2505
                        &RDMHTTPModule::LampStateHandler,
2506
                        response),
2507
      &error);
2508
  return error;
×
2509
}
×
2510

2511

2512
/**
2513
 * @brief Handle the response to lamp state call and build the response
2514
 */
2515
void RDMHTTPModule::LampStateHandler(HTTPResponse *response,
×
2516
                                     const ola::rdm::ResponseStatus &status,
2517
                                     uint8_t state) {
2518
  if (CheckForRDMError(response, status)) {
×
2519
    return;
×
2520
  }
2521

2522
  JsonSection section;
×
2523
  SelectItem *item = new SelectItem("Lamp State", GENERIC_UINT_FIELD);
×
2524

2525
  typedef struct {
×
2526
    string label;
2527
    ola::rdm::rdm_lamp_state state;
2528
  } values_s;
×
2529

2530
  values_s possible_values[] = {
×
2531
    {"Off", ola::rdm::LAMP_OFF},
×
2532
    {"On", ola::rdm::LAMP_ON},
2533
    {"Strike", ola::rdm::LAMP_STRIKE},
2534
    {"Standby", ola::rdm::LAMP_STANDBY}};
×
2535

2536
  for (unsigned int i = 0; i < sizeof(possible_values) / sizeof(values_s);
×
2537
       ++i) {
2538
    item->AddItem(possible_values[i].label, possible_values[i].state);
×
2539
    if (state == possible_values[i].state) {
×
2540
      item->SetSelectedOffset(i);
×
2541
    }
2542
  }
2543

2544
  section.AddItem(item);
×
2545
  RespondWithSection(response, section);
×
2546
}
×
2547

2548

2549
/**
2550
 * @brief Set the lamp state
2551
 */
2552
string RDMHTTPModule::SetLampState(const HTTPRequest *request,
×
2553
                                   HTTPResponse *response,
2554
                                   unsigned int universe_id,
2555
                                   const UID &uid) {
2556
  string lamp_state_str = request->GetParameter(GENERIC_UINT_FIELD);
×
2557
  uint8_t lamp_state;
×
2558
  if (!StringToInt(lamp_state_str, &lamp_state)) {
×
2559
    return "Invalid lamp state";
×
2560
  }
2561

2562
  string error;
×
2563
  m_rdm_api.SetLampState(
×
2564
      universe_id,
2565
      uid,
2566
      ola::rdm::ROOT_RDM_DEVICE,
2567
      lamp_state,
2568
      NewSingleCallback(this,
2569
                        &RDMHTTPModule::SetHandler,
2570
                        response),
2571
      &error);
2572
  return error;
×
2573
}
×
2574

2575

2576
/**
2577
 * @brief Handle the request for the lamp mode section
2578
 */
2579
string RDMHTTPModule::GetLampMode(OLA_UNUSED const HTTPRequest *request,
×
2580
                                  HTTPResponse *response,
2581
                                  unsigned int universe_id,
2582
                                  const UID &uid) {
2583
  string error;
×
2584
  m_rdm_api.GetLampMode(
×
2585
      universe_id,
2586
      uid,
2587
      ola::rdm::ROOT_RDM_DEVICE,
2588
      NewSingleCallback(this,
2589
                        &RDMHTTPModule::LampModeHandler,
2590
                        response),
2591
      &error);
2592
  return error;
×
2593
}
×
2594

2595

2596
/**
2597
 * @brief Handle the response to lamp mode call and build the response
2598
 */
2599
void RDMHTTPModule::LampModeHandler(HTTPResponse *response,
×
2600
                                    const ola::rdm::ResponseStatus &status,
2601
                                    uint8_t mode) {
2602
  if (CheckForRDMError(response, status)) {
×
2603
    return;
×
2604
  }
2605

2606
  JsonSection section;
×
2607
  SelectItem *item = new SelectItem("Lamp Mode", GENERIC_UINT_FIELD);
×
2608

2609
  typedef struct {
×
2610
    string label;
2611
    ola::rdm::rdm_lamp_mode mode;
2612
  } values_s;
×
2613

2614
  values_s possible_values[] = {
×
2615
    {"Off", ola::rdm::LAMP_ON_MODE_OFF},
×
2616
    {"DMX", ola::rdm::LAMP_ON_MODE_DMX},
2617
    {"On", ola::rdm::LAMP_ON_MODE_ON},
2618
    {"On After Calibration", ola::rdm::LAMP_ON_MODE_ON_AFTER_CAL}};
×
2619

2620
  for (unsigned int i = 0; i < sizeof(possible_values) / sizeof(values_s);
×
2621
       ++i) {
2622
    item->AddItem(possible_values[i].label, possible_values[i].mode);
×
2623
    if (mode == possible_values[i].mode) {
×
2624
      item->SetSelectedOffset(i);
×
2625
    }
2626
  }
2627

2628
  section.AddItem(item);
×
2629
  RespondWithSection(response, section);
×
2630
}
×
2631

2632

2633
/**
2634
 * @brief Set the lamp mode
2635
 */
2636
string RDMHTTPModule::SetLampMode(const HTTPRequest *request,
×
2637
                                  HTTPResponse *response,
2638
                                  unsigned int universe_id,
2639
                                  const UID &uid) {
2640
  string lamp_mode_str = request->GetParameter(GENERIC_UINT_FIELD);
×
2641
  uint8_t lamp_mode;
×
2642
  if (!StringToInt(lamp_mode_str, &lamp_mode)) {
×
2643
    return "Invalid lamp mode";
×
2644
  }
2645

2646
  string error;
×
2647
  m_rdm_api.SetLampMode(
×
2648
      universe_id,
2649
      uid,
2650
      ola::rdm::ROOT_RDM_DEVICE,
2651
      lamp_mode,
2652
      NewSingleCallback(this,
2653
                        &RDMHTTPModule::SetHandler,
2654
                        response),
2655
      &error);
2656
  return error;
×
2657
}
×
2658

2659

2660
/**
2661
 * @brief Handle the request for the device power cycles section
2662
 */
2663
string RDMHTTPModule::GetPowerCycles(OLA_UNUSED const HTTPRequest *request,
×
2664
                                     HTTPResponse *response,
2665
                                     unsigned int universe_id,
2666
                                     const UID &uid) {
2667
  string error;
×
2668
  m_rdm_api.GetDevicePowerCycles(
×
2669
      universe_id,
2670
      uid,
2671
      ola::rdm::ROOT_RDM_DEVICE,
2672
      NewSingleCallback(this,
2673
                        &RDMHTTPModule::GenericUIntHandler,
2674
                        response,
2675
                        string("Device Power Cycles")),
×
2676
      &error);
2677
  return error;
×
2678
}
×
2679

2680

2681
/**
2682
 * @brief Set the device power cycles
2683
 */
2684
string RDMHTTPModule::SetPowerCycles(const HTTPRequest *request,
×
2685
                                     HTTPResponse *response,
2686
                                     unsigned int universe_id,
2687
                                     const UID &uid) {
2688
  string power_cycles_str = request->GetParameter(GENERIC_UINT_FIELD);
×
2689
  uint32_t power_cycles;
×
2690

2691
  if (!StringToInt(power_cycles_str, &power_cycles)) {
×
2692
    return "Invalid power cycles";
×
2693
  }
2694

2695
  string error;
×
2696
  m_rdm_api.SetDevicePowerCycles(
×
2697
      universe_id,
2698
      uid,
2699
      ola::rdm::ROOT_RDM_DEVICE,
2700
      power_cycles,
2701
      NewSingleCallback(this,
2702
                        &RDMHTTPModule::SetHandler,
2703
                        response),
2704
      &error);
2705
  return error;
×
2706
}
×
2707

2708

2709

2710
/**
2711
 * @brief Handle the request for the display invert section.
2712
 */
2713
string RDMHTTPModule::GetDisplayInvert(HTTPResponse *response,
×
2714
                                       unsigned int universe_id,
2715
                                       const UID &uid) {
2716
  string error;
×
2717
  m_rdm_api.GetDisplayInvert(
×
2718
      universe_id,
2719
      uid,
2720
      ola::rdm::ROOT_RDM_DEVICE,
2721
      NewSingleCallback(this,
2722
                        &RDMHTTPModule::DisplayInvertHandler,
2723
                        response),
2724
      &error);
2725
  return error;
×
2726
}
×
2727

2728

2729
/**
2730
 * @brief Handle the response to display invert call and build the response
2731
 */
2732
void RDMHTTPModule::DisplayInvertHandler(
×
2733
    HTTPResponse *response,
2734
    const ola::rdm::ResponseStatus &status,
2735
    uint8_t value) {
2736
  if (CheckForRDMError(response, status)) {
×
2737
    return;
×
2738
  }
2739

2740
  JsonSection section;
×
2741
  SelectItem *item = new SelectItem("Display Invert", DISPLAY_INVERT_FIELD);
×
2742

2743
  item->AddItem("Off", ola::rdm::DISPLAY_INVERT_OFF);
×
2744
  item->AddItem("On", ola::rdm::DISPLAY_INVERT_ON);
×
2745
  item->AddItem("Auto", ola::rdm::DISPLAY_INVERT_AUTO);
×
2746

2747
  if (value < ola::rdm::DISPLAY_INVERT_MAX) {
×
2748
    item->SetSelectedOffset(value);
×
2749
  }
2750

2751
  section.AddItem(item);
×
2752
  RespondWithSection(response, section);
×
2753
}
×
2754

2755

2756
/**
2757
 * @brief Set the display invert.
2758
 */
2759
string RDMHTTPModule::SetDisplayInvert(const HTTPRequest *request,
×
2760
                                       HTTPResponse *response,
2761
                                       unsigned int universe_id,
2762
                                       const UID &uid) {
2763
  string invert_field = request->GetParameter(DISPLAY_INVERT_FIELD);
×
2764
  uint8_t display_invert;
×
2765
  if (!StringToInt(invert_field, &display_invert)) {
×
2766
    return "Invalid display invert";
×
2767
  }
2768

2769
  string error;
×
2770
  m_rdm_api.SetDisplayInvert(
×
2771
      universe_id,
2772
      uid,
2773
      ola::rdm::ROOT_RDM_DEVICE,
2774
      display_invert,
2775
      NewSingleCallback(this,
2776
                        &RDMHTTPModule::SetHandler,
2777
                        response),
2778
      &error);
2779
  return error;
×
2780
}
×
2781

2782

2783
/**
2784
 * @brief Handle the request for the display level section.
2785
 */
2786
string RDMHTTPModule::GetDisplayLevel(HTTPResponse *response,
×
2787
                                      unsigned int universe_id,
2788
                                      const UID &uid) {
2789
  string error;
×
2790
  m_rdm_api.GetDisplayLevel(
×
2791
      universe_id,
2792
      uid,
2793
      ola::rdm::ROOT_RDM_DEVICE,
2794
      NewSingleCallback(this,
2795
                        &RDMHTTPModule::DisplayLevelHandler,
2796
                        response),
2797
      &error);
2798
  return error;
×
2799
}
×
2800

2801

2802
/**
2803
 * @brief Handle the response to display level call and build the response
2804
 */
2805
void RDMHTTPModule::DisplayLevelHandler(HTTPResponse *response,
×
2806
                                        const ola::rdm::ResponseStatus &status,
2807
                                        uint8_t value) {
2808
  if (CheckForRDMError(response, status)) {
×
2809
    return;
×
2810
  }
2811

2812
  JsonSection section;
×
2813
  UIntItem *item = new UIntItem("Display Level", value, GENERIC_UINT_FIELD);
×
2814
  item->SetMin(std::numeric_limits<uint8_t>::min());
×
2815
  item->SetMax(std::numeric_limits<uint8_t>::max());
×
2816

2817
  section.AddItem(item);
×
2818
  RespondWithSection(response, section);
×
2819
}
×
2820

2821

2822
/**
2823
 * @brief Set the display level.
2824
 */
2825
string RDMHTTPModule::SetDisplayLevel(const HTTPRequest *request,
×
2826
                                      HTTPResponse *response,
2827
                                      unsigned int universe_id,
2828
                                      const UID &uid) {
2829
  string display_level_str = request->GetParameter(GENERIC_UINT_FIELD);
×
2830
  uint8_t display_level;
×
2831
  if (!StringToInt(display_level_str, &display_level)) {
×
2832
    return "Invalid display level";
×
2833
  }
2834

2835
  string error;
×
2836
  m_rdm_api.SetDisplayLevel(
×
2837
      universe_id,
2838
      uid,
2839
      ola::rdm::ROOT_RDM_DEVICE,
2840
      display_level,
2841
      NewSingleCallback(this,
2842
                        &RDMHTTPModule::SetHandler,
2843
                        response),
2844
      &error);
2845
  return error;
×
2846
}
×
2847

2848

2849
/**
2850
 * @brief Handle the request for the pan invert section.
2851
 */
2852
string RDMHTTPModule::GetPanInvert(HTTPResponse *response,
×
2853
                                   unsigned int universe_id,
2854
                                   const UID &uid) {
2855
  string error;
×
2856
  m_rdm_api.GetPanInvert(
×
2857
      universe_id,
2858
      uid,
2859
      ola::rdm::ROOT_RDM_DEVICE,
2860
      NewSingleCallback(this,
2861
                        &RDMHTTPModule::GenericUInt8BoolHandler,
2862
                        response,
2863
                        string("Pan Invert")),
×
2864
      &error);
2865
  return error;
×
2866
}
×
2867

2868

2869
/**
2870
 * @brief Set the pan invert.
2871
 */
2872
string RDMHTTPModule::SetPanInvert(const HTTPRequest *request,
×
2873
                                   HTTPResponse *response,
2874
                                   unsigned int universe_id,
2875
                                   const UID &uid) {
2876
  string mode = request->GetParameter(GENERIC_BOOL_FIELD);
×
2877

2878
  if (mode.empty()) {
×
2879
    return "Invalid mode value";
×
2880
  }
2881

2882
  string error;
×
2883
  m_rdm_api.SetPanInvert(
×
2884
      universe_id,
2885
      uid,
2886
      ola::rdm::ROOT_RDM_DEVICE,
2887
      mode == "1",
×
2888
      NewSingleCallback(this,
2889
                        &RDMHTTPModule::SetHandler,
2890
                        response),
2891
      &error);
2892
  return error;
×
2893
}
×
2894

2895

2896
/**
2897
 * @brief Handle the request for the tilt invert section.
2898
 */
2899
string RDMHTTPModule::GetTiltInvert(HTTPResponse *response,
×
2900
                                    unsigned int universe_id,
2901
                                    const UID &uid) {
2902
  string error;
×
2903
  m_rdm_api.GetTiltInvert(
×
2904
      universe_id,
2905
      uid,
2906
      ola::rdm::ROOT_RDM_DEVICE,
2907
      NewSingleCallback(this,
2908
                        &RDMHTTPModule::GenericUInt8BoolHandler,
2909
                        response,
2910
                        string("Tilt Invert")),
×
2911
      &error);
2912
  return error;
×
2913
}
×
2914

2915

2916
/**
2917
 * @brief Set the tilt invert.
2918
 */
2919
string RDMHTTPModule::SetTiltInvert(const HTTPRequest *request,
×
2920
                                    HTTPResponse *response,
2921
                                    unsigned int universe_id,
2922
                                    const UID &uid) {
2923
  string mode = request->GetParameter(GENERIC_BOOL_FIELD);
×
2924

2925
  if (mode.empty()) {
×
2926
    return "Invalid mode value";
×
2927
  }
2928

2929
  string error;
×
2930
  m_rdm_api.SetTiltInvert(
×
2931
      universe_id,
2932
      uid,
2933
      ola::rdm::ROOT_RDM_DEVICE,
2934
      mode == "1",
×
2935
      NewSingleCallback(this,
2936
                        &RDMHTTPModule::SetHandler,
2937
                        response),
2938
      &error);
2939
  return error;
×
2940
}
×
2941

2942

2943
/**
2944
 * @brief Handle the request for the pan/tilt swap section.
2945
 */
2946
string RDMHTTPModule::GetPanTiltSwap(HTTPResponse *response,
×
2947
                                     unsigned int universe_id,
2948
                                     const UID &uid) {
2949
  string error;
×
2950
  m_rdm_api.GetPanTiltSwap(
×
2951
      universe_id,
2952
      uid,
2953
      ola::rdm::ROOT_RDM_DEVICE,
2954
      NewSingleCallback(this,
2955
                        &RDMHTTPModule::GenericUInt8BoolHandler,
2956
                        response,
2957
                        string("Pan Tilt Swap")),
×
2958
      &error);
2959
  return error;
×
2960
}
×
2961

2962

2963
/**
2964
 * @brief Set the pan/tilt swap.
2965
 */
2966
string RDMHTTPModule::SetPanTiltSwap(const HTTPRequest *request,
×
2967
                                     HTTPResponse *response,
2968
                                     unsigned int universe_id,
2969
                                     const UID &uid) {
2970
  string mode = request->GetParameter(GENERIC_BOOL_FIELD);
×
2971

2972
  if (mode.empty()) {
×
2973
    return "Invalid mode value";
×
2974
  }
2975

2976
  string error;
×
2977
  m_rdm_api.SetPanTiltSwap(
×
2978
      universe_id,
2979
      uid,
2980
      ola::rdm::ROOT_RDM_DEVICE,
2981
      mode == "1",
×
2982
      NewSingleCallback(this,
2983
                        &RDMHTTPModule::SetHandler,
2984
                        response),
2985
      &error);
2986
  return error;
×
2987
}
×
2988

2989

2990
/**
2991
 * @brief Handle the request for the clock section.
2992
 */
2993
string RDMHTTPModule::GetClock(HTTPResponse *response,
×
2994
                               unsigned int universe_id,
2995
                               const UID &uid) {
2996
  string error;
×
2997
  m_rdm_api.GetClock(
×
2998
      universe_id,
2999
      uid,
3000
      ola::rdm::ROOT_RDM_DEVICE,
3001
      NewSingleCallback(this,
3002
                        &RDMHTTPModule::ClockHandler,
3003
                        response),
3004
      &error);
3005
  return error;
×
3006
}
×
3007

3008

3009
/**
3010
 * @brief Handle the response to clock call and build the response
3011
 */
3012
void RDMHTTPModule::ClockHandler(HTTPResponse *response,
×
3013
                                 const ola::rdm::ResponseStatus &status,
3014
                                 const ola::rdm::ClockValue &clock) {
3015
  if (CheckForRDMError(response, status)) {
×
3016
    return;
×
3017
  }
3018

3019
  JsonSection section;
×
3020
  ostringstream str;
×
3021
  str << std::setfill('0') << std::setw(2) << static_cast<int>(clock.hour)
×
3022
      << ":" << std::setw(2) << static_cast<int>(clock.minute) << ":"
×
3023
      << std::setw(2) << static_cast<int>(clock.second) << " "
×
3024
      << static_cast<int>(clock.day) << "/" << static_cast<int>(clock.month)
×
3025
      << "/" << clock.year;
×
3026

3027
  section.AddItem(new StringItem("Clock", str.str()));
×
3028
  section.AddItem(new HiddenItem("1", GENERIC_UINT_FIELD));
×
3029
  section.SetSaveButton("Sync to Server");
×
3030
  RespondWithSection(response, section);
×
3031
}
×
3032

3033

3034
/**
3035
 * @brief Sync the clock
3036
 */
3037
string RDMHTTPModule::SyncClock(HTTPResponse *response,
×
3038
                                unsigned int universe_id,
3039
                                const UID &uid) {
3040
  time_t now = time(NULL);
×
3041
  struct tm now_tm;
×
3042
#ifdef _WIN32
3043
  memcpy(&now_tm, localtime(&now), sizeof(now_tm));
3044
#else
3045
  localtime_r(&now, &now_tm);
×
3046
#endif  // _WIN32
3047
  ola::rdm::ClockValue clock_value;
×
3048

3049
  clock_value.year = now_tm.tm_year + 1900;
×
3050
  clock_value.month = now_tm.tm_mon + 1;
×
3051
  clock_value.day = now_tm.tm_mday;
×
3052
  clock_value.hour = now_tm.tm_hour;
×
3053
  clock_value.minute = now_tm.tm_min;
×
3054
  clock_value.second = now_tm.tm_sec;
×
3055
  string error;
×
3056
  m_rdm_api.SetClock(
×
3057
      universe_id,
3058
      uid,
3059
      ola::rdm::ROOT_RDM_DEVICE,
3060
      clock_value,
3061
      NewSingleCallback(this,
3062
                        &RDMHTTPModule::SetHandler,
3063
                        response),
3064
      &error);
3065
  return error;
×
3066
}
×
3067

3068

3069
/**
3070
 * @brief Handle the request for the identify device section.
3071
 */
3072
string RDMHTTPModule::GetIdentifyDevice(HTTPResponse *response,
×
3073
                                        unsigned int universe_id,
3074
                                        const UID &uid) {
3075
  string error;
×
3076
  m_rdm_api.GetIdentifyDevice(
×
3077
      universe_id,
3078
      uid,
3079
      ola::rdm::ROOT_RDM_DEVICE,
3080
      NewSingleCallback(this,
3081
                        &RDMHTTPModule::GenericBoolHandler,
3082
                        response,
3083
                        string("Identify Device")),
×
3084
      &error);
3085
  return error;
×
3086
}
×
3087

3088

3089
/*
3090
 * @brief Set identify device
3091
 */
3092
string RDMHTTPModule::SetIdentifyDevice(const HTTPRequest *request,
×
3093
                                        HTTPResponse *response,
3094
                                        unsigned int universe_id,
3095
                                        const UID &uid) {
3096
  string mode = request->GetParameter(GENERIC_BOOL_FIELD);
×
3097

3098
  if (mode.empty()) {
×
3099
    return "Invalid mode value";
×
3100
  }
3101

3102
  string error;
×
3103
  m_rdm_api.IdentifyDevice(
×
3104
      universe_id,
3105
      uid,
3106
      ola::rdm::ROOT_RDM_DEVICE,
3107
      mode == "1",
×
3108
      NewSingleCallback(this,
3109
                        &RDMHTTPModule::SetHandler,
3110
                        response),
3111
      &error);
3112
  return error;
×
3113
}
×
3114

3115

3116
/**
3117
 * @brief Handle the request for the power state section.
3118
 */
3119
string RDMHTTPModule::GetPowerState(HTTPResponse *response,
×
3120
                                    unsigned int universe_id,
3121
                                    const UID &uid) {
3122
  string error;
×
3123
  m_rdm_api.GetPowerState(
×
3124
      universe_id,
3125
      uid,
3126
      ola::rdm::ROOT_RDM_DEVICE,
3127
      NewSingleCallback(this,
3128
                        &RDMHTTPModule::PowerStateHandler,
3129
                        response),
3130
      &error);
3131
  return error;
×
3132
}
×
3133

3134

3135
/**
3136
 * @brief Handle the response to power state call and build the response
3137
 */
3138
void RDMHTTPModule::PowerStateHandler(HTTPResponse *response,
×
3139
                                      const ola::rdm::ResponseStatus &status,
3140
                                      uint8_t value) {
3141
  if (CheckForRDMError(response, status)) {
×
3142
    return;
×
3143
  }
3144

3145
  JsonSection section;
×
3146
  SelectItem *item = new SelectItem("Power State", GENERIC_UINT_FIELD);
×
3147

3148
  typedef struct {
×
3149
    string label;
3150
    ola::rdm::rdm_power_state state;
3151
  } values_s;
×
3152

3153
  values_s possible_values[] = {
×
3154
    {"Full Off", ola::rdm::POWER_STATE_FULL_OFF},
×
3155
    {"Shutdown", ola::rdm::POWER_STATE_SHUTDOWN},
3156
    {"Standby", ola::rdm::POWER_STATE_STANDBY},
3157
    {"Normal", ola::rdm::POWER_STATE_NORMAL}};
×
3158

3159
  for (unsigned int i = 0; i < sizeof(possible_values) / sizeof(values_s);
×
3160
       ++i) {
3161
    item->AddItem(possible_values[i].label, possible_values[i].state);
×
3162
    if (value == possible_values[i].state) {
×
3163
      item->SetSelectedOffset(i);
×
3164
    }
3165
  }
3166

3167
  section.AddItem(item);
×
3168
  RespondWithSection(response, section);
×
3169
}
×
3170

3171

3172
/*
3173
 * @brief Set the power state.
3174
 */
3175
string RDMHTTPModule::SetPowerState(const HTTPRequest *request,
×
3176
                                    HTTPResponse *response,
3177
                                    unsigned int universe_id,
3178
                                    const UID &uid) {
3179
  string power_state_str = request->GetParameter(GENERIC_UINT_FIELD);
×
3180
  uint8_t power_state;
×
3181
  ola::rdm::rdm_power_state power_state_enum;
×
3182
  if (!StringToInt(power_state_str, &power_state) ||
×
3183
      !ola::rdm::UIntToPowerState(power_state, &power_state_enum)) {
×
3184
    return "Invalid power state";
×
3185
  }
3186

3187
  string error;
×
3188
  m_rdm_api.SetPowerState(
×
3189
      universe_id,
3190
      uid,
3191
      ola::rdm::ROOT_RDM_DEVICE,
3192
      power_state_enum,
3193
      NewSingleCallback(this,
3194
                        &RDMHTTPModule::SetHandler,
3195
                        response),
3196
      &error);
3197
  return error;
×
3198
}
×
3199

3200

3201
/**
3202
 * @brief Handle the request for the device reset section.
3203
 */
3204
string RDMHTTPModule::GetResetDevice(HTTPResponse *response) {
×
3205
  JsonSection section = JsonSection(false);
×
3206
  SelectItem *item = new SelectItem("Reset Device", GENERIC_UINT_FIELD);
×
3207

3208
  typedef struct {
×
3209
    string label;
3210
    ola::rdm::rdm_reset_device_mode state;
3211
  } values_s;
×
3212

3213
  values_s possible_values[] = {
×
3214
    {"Warm Reset", ola::rdm::RESET_WARM},
×
3215
    {"Cold Reset", ola::rdm::RESET_COLD}};
×
3216

3217
  for (unsigned int i = 0; i < sizeof(possible_values) / sizeof(values_s);
×
3218
       ++i) {
3219
    item->AddItem(possible_values[i].label, possible_values[i].state);
×
3220
  }
3221

3222
  section.AddItem(item);
×
3223
  section.SetSaveButton("Reset Device");
×
3224
  RespondWithSection(response, section);
×
3225

3226
  return "";
×
3227
}
×
3228

3229

3230
/*
3231
 * @brief Set the reset device.
3232
 */
3233
string RDMHTTPModule::SetResetDevice(const HTTPRequest *request,
×
3234
                                     HTTPResponse *response,
3235
                                     unsigned int universe_id,
3236
                                     const UID &uid) {
3237
  string reset_device_str = request->GetParameter(GENERIC_UINT_FIELD);
×
3238
  uint8_t reset_device;
×
3239
  ola::rdm::rdm_reset_device_mode reset_device_enum;
×
3240
  if (!StringToInt(reset_device_str, &reset_device) ||
×
3241
      !ola::rdm::UIntToResetDevice(reset_device, &reset_device_enum)) {
×
3242
    return "Invalid reset device";
×
3243
  }
3244

3245
  string error;
×
3246
  m_rdm_api.SetResetDevice(
×
3247
      universe_id,
3248
      uid,
3249
      ola::rdm::ROOT_RDM_DEVICE,
3250
      reset_device_enum,
3251
      NewSingleCallback(this,
3252
                        &RDMHTTPModule::SetHandler,
3253
                        response),
3254
      &error);
3255
  return error;
×
3256
}
×
3257

3258

3259
/**
3260
 * @brief Handle the request for the DNS Hostname.
3261
 */
3262
string RDMHTTPModule::GetDnsHostname(HTTPResponse *response,
×
3263
                                     unsigned int universe_id,
3264
                                     const UID &uid) {
3265
  string error;
×
3266
  m_rdm_api.GetDnsHostname(
×
3267
      universe_id,
3268
      uid,
3269
      ola::rdm::ROOT_RDM_DEVICE,
3270
      NewSingleCallback(this,
3271
                        &RDMHTTPModule::GetDnsHostnameHandler,
3272
                        response),
3273
      &error);
3274
  return error;
×
3275
}
×
3276

3277

3278
/**
3279
 * @brief Handle the response to a DNS hostname call and build the response
3280
 */
3281
void RDMHTTPModule::GetDnsHostnameHandler(
×
3282
    HTTPResponse *response,
3283
    const ola::rdm::ResponseStatus &status,
3284
    const string &label) {
3285
  if (CheckForRDMError(response, status)) {
×
3286
    return;
×
3287
  }
3288

3289
  JsonSection section;
×
3290
  section.AddItem(new StringItem("Hostname", label, GENERIC_STRING_FIELD));
×
3291
  RespondWithSection(response, section);
×
3292
}
×
3293

3294

3295
/*
3296
 * @brief Set the DNS hostname
3297
 */
3298
string RDMHTTPModule::SetDnsHostname(const HTTPRequest *request,
×
3299
                                     HTTPResponse *response,
3300
                                     unsigned int universe_id,
3301
                                     const UID &uid) {
3302
  string label = request->GetParameter(GENERIC_STRING_FIELD);
×
3303
  string error;
×
3304
  m_rdm_api.SetDnsHostname(
×
3305
      universe_id,
3306
      uid,
3307
      ola::rdm::ROOT_RDM_DEVICE,
3308
      label,
3309
      NewSingleCallback(this,
3310
                        &RDMHTTPModule::SetHandler,
3311
                        response),
3312
      &error);
3313
  return error;
×
3314
}
×
3315

3316

3317
/**
3318
 * @brief Handle the request for the DNS domain name.
3319
 */
3320
string RDMHTTPModule::GetDnsDomainName(HTTPResponse *response,
×
3321
                                       unsigned int universe_id,
3322
                                       const UID &uid) {
3323
  string error;
×
3324
  m_rdm_api.GetDnsDomainName(
×
3325
      universe_id,
3326
      uid,
3327
      ola::rdm::ROOT_RDM_DEVICE,
3328
      NewSingleCallback(this,
3329
                        &RDMHTTPModule::GetDnsDomainNameHandler,
3330
                        response),
3331
      &error);
3332
  return error;
×
3333
}
×
3334

3335

3336
/**
3337
 * @brief Handle the response to a DNS domain name call and build the response
3338
 */
3339
void RDMHTTPModule::GetDnsDomainNameHandler(
×
3340
    HTTPResponse *response,
3341
    const ola::rdm::ResponseStatus &status,
3342
    const string &label) {
3343
  if (CheckForRDMError(response, status)) {
×
3344
    return;
×
3345
  }
3346

3347
  JsonSection section;
×
3348
  section.AddItem(new StringItem("Domain Name", label, GENERIC_STRING_FIELD));
×
3349
  RespondWithSection(response, section);
×
3350
}
×
3351

3352

3353
/*
3354
 * @brief Set the DNS domain name
3355
 */
3356
string RDMHTTPModule::SetDnsDomainName(const HTTPRequest *request,
×
3357
                                       HTTPResponse *response,
3358
                                       unsigned int universe_id,
3359
                                       const UID &uid) {
3360
  string label = request->GetParameter(GENERIC_STRING_FIELD);
×
3361
  string error;
×
3362
  m_rdm_api.SetDnsDomainName(
×
3363
      universe_id,
3364
      uid,
3365
      ola::rdm::ROOT_RDM_DEVICE,
3366
      label,
3367
      NewSingleCallback(this,
3368
                        &RDMHTTPModule::SetHandler,
3369
                        response),
3370
      &error);
3371
  return error;
×
3372
}
×
3373

3374
/**
3375
 * @brief Handle the request for the dimmer curve section.
3376
 */
3377
string RDMHTTPModule::GetCurve(OLA_UNUSED const HTTPRequest *request,
×
3378
                               HTTPResponse *response,
3379
                               unsigned int universe_id,
3380
                               const UID &uid,
3381
                               bool include_descriptions) {
3382
  string error;
×
3383

3384
  curve_info *info = new curve_info;
×
3385
  info->universe_id = universe_id;
×
3386
  info->uid = new UID(uid);
×
3387
  info->include_descriptions = include_descriptions;
×
3388
  info->active = 0;
×
3389
  info->next = 1;
×
3390
  info->total = 0;
×
3391

3392
  m_rdm_api.GetCurve(
×
3393
      universe_id,
3394
      uid,
3395
      ola::rdm::ROOT_RDM_DEVICE,
3396
      NewSingleCallback(this,
3397
                        &RDMHTTPModule::GetCurveHandler,
3398
                        response,
3399
                        info),
3400
      &error);
3401
  return error;
×
3402
}
×
3403

3404
/**
3405
 * @brief Handle the response to a dimmer curve call and build the curve info
3406
 * object
3407
 */
3408
void RDMHTTPModule::GetCurveHandler(
×
3409
    HTTPResponse *response,
3410
    curve_info *info,
3411
    const ola::rdm::ResponseStatus &status,
3412
    uint8_t active_curve,
3413
    uint8_t curve_count) {
3414
  if (CheckForRDMError(response, status)) {
×
3415
    delete info->uid;
×
3416
    delete info;
×
3417
    return;
×
3418
  }
3419

3420
  info->active = active_curve;
×
3421
  info->total = curve_count;
×
3422

3423
  if (info->include_descriptions) {
×
3424
    GetNextCurveDescription(response, info);
×
3425
  } else {
3426
    SendCurveResponse(response, info);
×
3427
  }
3428
}
3429

3430
/**
3431
 * @brief Handle the response to a curve description call and add to curve
3432
 * info object
3433
 */
3434
void RDMHTTPModule::GetNextCurveDescription(HTTPResponse *response,
×
3435
                                            curve_info *info) {
3436
  string error;
×
3437
  while (info->next <= info->total) {
×
3438
    bool r = m_rdm_api.GetCurveDescription(
×
3439
        info->universe_id,
3440
        *(info->uid),
×
3441
        ola::rdm::ROOT_RDM_DEVICE,
3442
        info->next,
×
3443
        NewSingleCallback(this,
3444
                          &RDMHTTPModule::GetCurveDescriptionHandler,
3445
                          response,
3446
                          info),
3447
        &error);
3448
    if (r) {
×
3449
      return;
×
3450
    }
3451

3452
    info->next++;
×
3453
  }
3454

3455
  SendCurveResponse(response, info);
×
3456
}
×
3457

3458
void RDMHTTPModule::GetCurveDescriptionHandler(
×
3459
    HTTPResponse *response,
3460
    curve_info *info,
3461
    const ola::rdm::ResponseStatus &status,
3462
    OLA_UNUSED uint8_t curve,
3463
    const string &resp_description) {
3464
  string description = "";
×
3465

3466
  if (CheckForRDMSuccess(status)) {
×
3467
    description = resp_description;
×
3468
  }
3469

3470
  info->curve_descriptions.push_back(description);
×
3471

3472
  if (info->next == info->total) {
×
3473
    SendCurveResponse(response, info);
×
3474
  } else {
3475
    info->next++;
×
3476
    GetNextCurveDescription(response, info);
×
3477
  }
3478
}
×
3479

3480
/**
3481
 * @brief Build the curve http response
3482
 */
3483
void RDMHTTPModule::SendCurveResponse(HTTPResponse *response,
×
3484
                                      curve_info *info) {
3485
  JsonSection section;
×
3486
  SelectItem *item = new SelectItem("Active Curve", GENERIC_UINT_FIELD);
×
3487

3488
  for (unsigned int i = 1; i <= info->total; i++) {
×
3489
    if (i <= info->curve_descriptions.size() &&
×
3490
        !info->curve_descriptions[i - 1].empty()) {
×
3491
      ostringstream str;
×
3492
      str << info->curve_descriptions[i - 1] << " ("
×
3493
          << i << ")";
×
3494
      item->AddItem(str.str(), i);
×
3495
    } else {
×
3496
      item->AddItem(IntToString(i), i);
×
3497
    }
3498
  }
3499
  item->SetSelectedOffset(info->active - 1);
×
3500

3501
  section.AddItem(item);
×
3502
  section.AddItem(new StringItem("Available Curves",
×
3503
                                 IntToString(info->total)));
×
3504
  RespondWithSection(response, section);
×
3505
}
×
3506

3507
/**
3508
 * @brief Set the dimmer curve
3509
 */
3510
string RDMHTTPModule::SetCurve(const HTTPRequest *request,
×
3511
                                     HTTPResponse *response,
3512
                                     unsigned int universe_id,
3513
                                     const UID &uid) {
3514
  string curve_str = request->GetParameter(GENERIC_UINT_FIELD);
×
3515
  uint8_t curve;
×
3516

3517
  if (!StringToInt(curve_str, &curve)) {
×
3518
    return "Invalid curve";
×
3519
  }
3520

3521
  string error;
×
3522
  m_rdm_api.SetCurve(
×
3523
      universe_id,
3524
      uid,
3525
      ola::rdm::ROOT_RDM_DEVICE,
3526
      curve,
3527
      NewSingleCallback(this,
3528
                        &RDMHTTPModule::SetHandler,
3529
                        response),
3530
      &error);
3531
  return error;
×
3532
}
×
3533

3534
/**
3535
 * @brief Handle the request for Dimmer Info.
3536
 */
3537
string RDMHTTPModule::GetDimmerInfo(HTTPResponse *response,
×
3538
                                    unsigned int universe_id,
3539
                                    const UID &uid) {
3540
  string error;
×
3541
  m_rdm_api.GetDimmerInfo(
×
3542
    universe_id,
3543
    uid,
3544
    ola::rdm::ROOT_RDM_DEVICE,
3545
    NewSingleCallback(this,
3546
                      &RDMHTTPModule::GetDimmerInfoHandler,
3547
                      response),
3548
    &error);
3549
  return error;
×
3550
}
×
3551

3552
/*
3553
 * @brief Handle the response to a dimmer info call and build the response
3554
 */
3555
void RDMHTTPModule::GetDimmerInfoHandler(
×
3556
    HTTPResponse *response,
3557
    const ola::rdm::ResponseStatus &status,
3558
    const ola::rdm::DimmerInfoDescriptor &info) {
3559
  if (CheckForRDMError(response, status)) {
×
3560
    return;
×
3561
  }
3562

3563
  JsonSection section;
×
3564
  section.AddItem(new UIntItem("Minimum Level Lower Limit",
×
3565
                               info.min_level_lower_limit));
×
3566
  section.AddItem(new UIntItem("Minimum Level Upper Limit",
×
3567
                               info.min_level_upper_limit));
×
3568
  section.AddItem(new UIntItem("Maximum Level Lower Limit",
×
3569
                               info.max_level_lower_limit));
×
3570
  section.AddItem(new UIntItem("Maximum Level Upper Limit",
×
3571
                               info.max_level_upper_limit));
×
3572
  section.AddItem(new UIntItem("# of Supported Curves", info.curves_supported));
×
3573
  section.AddItem(new UIntItem("Levels Resolution", info.resolution));
×
3574
  section.AddItem(new BoolItem("Split Levels Supported",
×
3575
                               info.split_levels_supported));
×
3576

3577
  RespondWithSection(response, section);
×
3578
}
×
3579

3580

3581
/**
3582
 * @brief Handle the request for Dimmer Minimum Levels.
3583
 */
3584
string RDMHTTPModule::GetDimmerMinimumLevels(HTTPResponse *response,
×
3585
                                             unsigned int universe_id,
3586
                                             const UID &uid) {
3587
  string error;
×
3588
  m_rdm_api.GetDimmerMinimumLevels(
×
3589
    universe_id,
3590
    uid,
3591
    ola::rdm::ROOT_RDM_DEVICE,
3592
    NewSingleCallback(this,
3593
                      &RDMHTTPModule::GetDimmerMinimumLevelsHandler,
3594
                      response),
3595
    &error);
3596
  return error;
×
3597
}
×
3598

3599

3600
/*
3601
 * @brief Handle the response to a dimmer minimum levels and build the response
3602
 */
3603
void RDMHTTPModule::GetDimmerMinimumLevelsHandler(
×
3604
    HTTPResponse *response,
3605
    const ola::rdm::ResponseStatus &status,
3606
    const ola::rdm::DimmerMinimumDescriptor &info) {
3607
  if (CheckForRDMError(response, status)) {
×
3608
    return;
×
3609
  }
3610

3611
  JsonSection section;
×
3612
  section.AddItem(new UIntItem("Minimum Level - Increasing",
×
3613
                               info.min_level_increasing,
×
3614
                               DIMMER_MINIMUM_INCREASING_FIELD));
×
3615
  section.AddItem(new UIntItem("Minimum Level - Decreasing",
×
3616
                               info.min_level_decreasing,
×
3617
                               DIMMER_MINIMUM_DECREASING_FIELD));
×
3618
  section.AddItem(new BoolItem("On Below Minimum", info.on_below_min,
×
3619
                               GENERIC_BOOL_FIELD));
×
3620

3621
  RespondWithSection(response, section);
×
3622
}
×
3623

3624

3625
/**
3626
 * @brief Set the dimmer minimum levels
3627
 */
3628
string RDMHTTPModule::SetDimmerMinimumLevels(const HTTPRequest *request,
×
3629
                                             HTTPResponse *response,
3630
                                             unsigned int universe_id,
3631
                                             const UID &uid) {
3632
  string raw_value = request->GetParameter(DIMMER_MINIMUM_INCREASING_FIELD);
×
3633
  uint16_t min_increasing, min_decreasing;
×
3634

3635
  if (!StringToInt(raw_value, &min_increasing)) {
×
3636
    return "Invalid minimum level - increasing";
×
3637
  }
3638

3639
  raw_value = request->GetParameter(DIMMER_MINIMUM_DECREASING_FIELD);
×
3640

3641
  if (!StringToInt(raw_value, &min_decreasing)) {
×
3642
    return "Invalid minimum level - decreasing";
×
3643
  }
3644

3645
  raw_value = request->GetParameter(GENERIC_BOOL_FIELD);
×
3646

3647
  if (raw_value.empty()) {
×
3648
    return "Invalid on below minimum value";
×
3649
  }
3650

3651
  string error;
×
3652
  m_rdm_api.SetDimmerMinimumLevels(
×
3653
      universe_id,
3654
      uid,
3655
      ola::rdm::ROOT_RDM_DEVICE,
3656
      min_increasing,
3657
      min_decreasing,
3658
      raw_value == "1",
×
3659
      NewSingleCallback(this,
3660
                        &RDMHTTPModule::SetHandler,
3661
                        response),
3662
      &error);
3663
  return error;
×
3664
}
×
3665

3666
/**
3667
 * @brief Handle the request for the dimmer maximum levels
3668
 */
3669
string RDMHTTPModule::GetDimmerMaximumLevel(HTTPResponse *response,
×
3670
                                            unsigned int universe_id,
3671
                                            const UID &uid) {
3672
  string error;
×
3673

3674
  m_rdm_api.GetDimmerMaximumLevel(
×
3675
      universe_id,
3676
      uid,
3677
      ola::rdm::ROOT_RDM_DEVICE,
3678
      NewSingleCallback(this,
3679
                        &RDMHTTPModule::GetDimmerMaximumLevelHandler,
3680
                        response),
3681
      &error);
3682
  return error;
×
3683
}
×
3684

3685
/*
3686
 * @brief Handle the response to a dimmer maximum call and build the response
3687
 */
3688
void RDMHTTPModule::GetDimmerMaximumLevelHandler(
×
3689
    HTTPResponse *response,
3690
    const ola::rdm::ResponseStatus &status,
3691
    uint16_t maximum_level) {
3692
  if (CheckForRDMError(response, status)) {
×
3693
    return;
×
3694
  }
3695

3696
  JsonSection section;
×
3697
  section.AddItem(new UIntItem("Maximum Level",
×
3698
                               maximum_level, GENERIC_UINT_FIELD));
×
3699

3700
  RespondWithSection(response, section);
×
3701
}
×
3702

3703
/*
3704
 * @brief Set the Dimmer maximum level
3705
 */
3706
string RDMHTTPModule::SetDimmerMaximumLevel(const HTTPRequest *request,
×
3707
                                      HTTPResponse *response,
3708
                                      unsigned int universe_id,
3709
                                      const UID &uid) {
3710
  string s_max_level = request->GetParameter(GENERIC_UINT_FIELD);
×
3711
  uint16_t maximum_level;
×
3712

3713
  if (!StringToInt(s_max_level, &maximum_level)) {
×
3714
    return "Invalid maximum level";
×
3715
  }
3716

3717
  string error;
×
3718
  m_rdm_api.SetDimmerMaximumLevel(
×
3719
      universe_id,
3720
      uid,
3721
      ola::rdm::ROOT_RDM_DEVICE,
3722
      maximum_level,
3723
      NewSingleCallback(this,
3724
                        &RDMHTTPModule::SetHandler,
3725
                        response),
3726
      &error);
3727
  return error;
×
3728
}
×
3729

3730
/**
3731
 * @brief Check if the id URL param exists and is valid.
3732
 */
3733
bool RDMHTTPModule::CheckForInvalidId(const HTTPRequest *request,
×
3734
                                      unsigned int *universe_id) {
3735
  string uni_id = request->GetParameter(ID_KEY);
×
3736
  if (!StringToInt(uni_id, universe_id)) {
×
3737
    OLA_INFO << "Invalid universe id: " << uni_id;
×
3738
    return false;
×
3739
  }
3740
  return true;
3741
}
×
3742

3743

3744
/**
3745
 * @brief Check that the uid URL param exists and is valid.
3746
 */
3747
bool RDMHTTPModule::CheckForInvalidUid(const HTTPRequest *request,
×
3748
                                       UID **uid) {
3749
  string uid_string = request->GetParameter(UID_KEY);
×
3750
  *uid = UID::FromString(uid_string);
×
3751
  if (*uid == NULL) {
×
3752
    OLA_INFO << "Invalid UID: " << uid_string;
×
3753
    return false;
×
3754
  }
3755
  return true;
3756
}
×
3757

3758

3759
/**
3760
 * @brief Get the sub device from the HTTP request, or return ROOT_DEVICE if it
3761
 *   isn't valid.
3762
 */
3763
uint16_t RDMHTTPModule::SubDeviceOrRoot(const HTTPRequest *request) {
×
3764
  string sub_device_str = request->GetParameter(SUB_DEVICE_FIELD);
×
3765
  uint16_t sub_device;
×
3766

3767
  if (StringToInt(sub_device_str, &sub_device)) {
×
3768
    return sub_device;
×
3769
  }
3770

3771
  OLA_INFO << "Invalid sub device " << sub_device_str;
×
3772
  return ola::rdm::ROOT_RDM_DEVICE;
×
3773
}
×
3774

3775

3776
/*
3777
 * @brief Check the response to a Set RDM call and build the response.
3778
 */
3779
void RDMHTTPModule::SetHandler(
×
3780
    HTTPResponse *response,
3781
    const ola::rdm::ResponseStatus &status) {
3782
  string error;
×
3783
  CheckForRDMSuccessWithError(status, &error);
×
3784
  RespondWithError(response, error);
×
3785
}
×
3786

3787

3788
/*
3789
 * @brief Build a response to a RDM call that returns a uint32_t
3790
 */
3791
void RDMHTTPModule::GenericUIntHandler(HTTPResponse *response,
×
3792
                                       string description,
3793
                                       const ola::rdm::ResponseStatus &status,
3794
                                       uint32_t value) {
3795
  if (CheckForRDMError(response, status)) {
×
3796
    return;
×
3797
  }
3798

3799
  JsonSection section;
×
3800
  section.AddItem(new UIntItem(description, value, GENERIC_UINT_FIELD));
×
3801
  RespondWithSection(response, section);
×
3802
}
×
3803

3804

3805
/*
3806
 * @brief Build a response to a RDM call that returns a bool
3807
 */
3808
void RDMHTTPModule::GenericUInt8BoolHandler(
×
3809
    HTTPResponse *response,
3810
    string description,
3811
    const ola::rdm::ResponseStatus &status,
3812
    uint8_t value) {
3813
  GenericBoolHandler(response, description, status, value > 0);
×
3814
}
×
3815

3816

3817
/*
3818
 * @brief Build a response to a RDM call that returns a bool
3819
 */
3820
void RDMHTTPModule::GenericBoolHandler(HTTPResponse *response,
×
3821
                                       string description,
3822
                                       const ola::rdm::ResponseStatus &status,
3823
                                       bool value) {
3824
  if (CheckForRDMError(response, status)) {
×
3825
    return;
×
3826
  }
3827

3828
  JsonSection section;
×
3829
  section.AddItem(new BoolItem(description, value, GENERIC_BOOL_FIELD));
×
3830
  RespondWithSection(response, section);
×
3831
}
×
3832

3833
/**
3834
 * @brief Check for an RDM error, and if it occurs, return a JSON response.
3835
 * @return true if an error occurred.
3836
 */
3837
bool RDMHTTPModule::CheckForRDMError(HTTPResponse *response,
×
3838
                                     const ola::rdm::ResponseStatus &status) {
3839
  string error;
×
3840
  if (!CheckForRDMSuccessWithError(status, &error)) {
×
3841
    RespondWithError(response, error);
×
3842
    return true;
3843
  }
3844
  return false;
3845
}
×
3846

3847

3848

3849
int RDMHTTPModule::RespondWithError(HTTPResponse *response,
×
3850
                                    const string &error) {
3851
  response->SetNoCache();
×
3852
  response->SetContentType(HTTPServer::CONTENT_TYPE_PLAIN);
×
3853

3854
  JsonObject json;
×
3855
  json.Add("error", error);
×
3856
  int r = response->SendJson(json);
×
3857
  delete response;
×
3858
  return r;
×
3859
}
×
3860

3861

3862
/**
3863
 * @brief Build & send a response from a JsonSection
3864
 */
3865
void RDMHTTPModule::RespondWithSection(HTTPResponse *response,
×
3866
                                       const ola::web::JsonSection &section) {
3867
  response->SetNoCache();
×
3868
  response->SetContentType(HTTPServer::CONTENT_TYPE_PLAIN);
×
3869
  response->Append(section.AsString());
×
3870
  response->Send();
×
3871
  delete response;
×
3872
}
×
3873

3874

3875
/*
3876
 * @brief Check the success of an RDM command
3877
 * @returns true if this command was ok, false otherwise.
3878
 */
3879
bool RDMHTTPModule::CheckForRDMSuccess(
×
3880
    const ola::rdm::ResponseStatus &status) {
3881
  string error;
×
3882
  if (!CheckForRDMSuccessWithError(status, &error)) {
×
3883
    OLA_INFO << error;
×
3884
    return false;
×
3885
  }
3886
  return true;
3887
}
×
3888

3889

3890
/*
3891
 * @brief Check the success of an RDM command or return an error message.
3892
 *
3893
 * At the moment we're very strict in this method, some day this should be
3894
 * relaxed to handle the corner cases.
3895
 * @returns true if this command returns an ACK. false for any other condition.
3896
 */
3897
bool RDMHTTPModule::CheckForRDMSuccessWithError(
×
3898
    const ola::rdm::ResponseStatus &status,
3899
    string *error) {
3900
  ostringstream str;
×
3901
  if (!status.error.empty()) {
×
3902
    str << "RDM command error: " << status.error;
×
3903
    if (error) {
×
3904
      *error = str.str();
×
3905
    }
3906
    return false;
×
3907
  }
3908

3909
  // TODO(simon): One day we should handle broadcast responses, ack timers etc.
3910
  if (status.response_code != ola::rdm::RDM_COMPLETED_OK) {
×
3911
    if (error) {
×
3912
      *error = ola::rdm::StatusCodeToString(status.response_code);
×
3913
    }
3914
  } else {
3915
    switch (status.response_type) {
×
3916
      case ola::rdm::RDM_ACK:
3917
        return true;
3918
      case ola::rdm::RDM_ACK_TIMER:
×
3919
        str << "Got ACK Timer for " << status.AckTimer() << " ms";
×
3920
        if (error) {
×
3921
          *error = str.str();
×
3922
        }
3923
        break;
3924
      case ola::rdm::RDM_NACK_REASON:
×
3925
        str << "Request was NACKED with code: " <<
×
3926
          ola::rdm::NackReasonToString(status.NackReason());
×
3927
        OLA_INFO << str.str();
×
3928
        if (error) {
×
3929
          *error = str.str();
×
3930
        }
3931
    }
3932
  }
3933
  return false;
3934
}
×
3935

3936

3937
/*
3938
 * @brief Handle the RDM discovery response
3939
 * @param response the HTTPResponse that is associated with the request.
3940
 * @param error an error string.
3941
 */
3942
void RDMHTTPModule::HandleBoolResponse(HTTPResponse *response,
×
3943
                                       const string &error) {
3944
  if (!error.empty()) {
×
3945
    m_server->ServeError(response, error);
×
3946
    return;
×
3947
  }
3948
  response->SetNoCache();
×
3949
  response->SetContentType(HTTPServer::CONTENT_TYPE_PLAIN);
×
3950
  response->Append("ok");
×
3951
  response->Send();
×
3952
  delete response;
×
3953
}
3954

3955

3956
/**
3957
 * @brief Add a section to the supported section list
3958
 */
3959
void RDMHTTPModule::AddSection(vector<section_info> *sections,
×
3960
                               const string &section_id,
3961
                               const string &section_name,
3962
                               const string &hint) {
3963
  section_info info = {section_id, section_name, hint};
×
3964
  sections->push_back(info);
×
3965
}
×
3966
}  // 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