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

OpenLightingProject / ola / 16911433572

12 Aug 2025 02:08PM UTC coverage: 45.869% (-0.04%) from 45.909%
16911433572

Pull #1739

github

web-flow
Merge 02faeaa2d into 3566c28d9
Pull Request #1739: New web UI, store highest channel number used

7157 of 16316 branches covered (43.86%)

20915 of 45597 relevant lines covered (45.87%)

52.03 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::DISPLAY_INVERT_FIELD[] = "invert";
89
const char RDMHTTPModule::GENERIC_BOOL_FIELD[] = "bool";
90
const char RDMHTTPModule::GENERIC_STRING_FIELD[] = "string";
91
const char RDMHTTPModule::GENERIC_UINT_FIELD[] = "int";
92
const char RDMHTTPModule::IDENTIFY_DEVICE_FIELD[] = "identify_device";
93
const char RDMHTTPModule::LABEL_FIELD[] = "label";
94
const char RDMHTTPModule::LANGUAGE_FIELD[] = "language";
95
const char RDMHTTPModule::RECORD_SENSOR_FIELD[] = "record";
96
const char RDMHTTPModule::SUB_DEVICE_FIELD[] = "sub_device";
97

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

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

161
RDMHTTPModule::RDMHTTPModule(HTTPServer *http_server,
×
162
                             client::OlaClient *client)
×
163
    : m_server(http_server),
×
164
      m_client(client),
×
165
      m_shim(client),
×
166
      m_rdm_api(&m_shim),
×
167
      m_pid_store(NULL) {
×
168

169
  m_server->RegisterHandler(
×
170
      "/rdm/run_discovery",
171
      NewCallback(this, &RDMHTTPModule::RunRDMDiscovery));
172
  m_server->RegisterHandler(
×
173
      "/json/rdm/uids",
174
      NewCallback(this, &RDMHTTPModule::JsonUIDs));
175
  m_server->RegisterHandler(
×
176
      "/json/rdm/uid_info",
177
      NewCallback(this, &RDMHTTPModule::JsonUIDInfo));
178
  // Deprecated for clarity, use uid_identify_device instead
179
  m_server->RegisterHandler(
×
180
      "/json/rdm/uid_identify",
181
      NewCallback(this, &RDMHTTPModule::JsonUIDIdentifyDevice));
182
  m_server->RegisterHandler(
×
183
      "/json/rdm/uid_identify_device",
184
      NewCallback(this, &RDMHTTPModule::JsonUIDIdentifyDevice));
185
  m_server->RegisterHandler(
×
186
      "/json/rdm/uid_personalities",
187
      NewCallback(this, &RDMHTTPModule::JsonUIDPersonalities));
188
  m_server->RegisterHandler(
×
189
      "/json/rdm/supported_pids",
190
      NewCallback(this, &RDMHTTPModule::JsonSupportedPIDs));
191
  m_server->RegisterHandler(
×
192
      "/json/rdm/supported_sections",
193
      NewCallback(this, &RDMHTTPModule::JsonSupportedSections));
194
  m_server->RegisterHandler(
×
195
      "/json/rdm/section_info",
196
      NewCallback(this, &RDMHTTPModule::JsonSectionInfo));
197
  m_server->RegisterHandler(
×
198
      "/json/rdm/set_section_info",
199
      NewCallback(this, &RDMHTTPModule::JsonSaveSectionInfo));
200
}
×
201

202

203
/*
204
 * Teardown
205
 */
206
RDMHTTPModule::~RDMHTTPModule() {
×
207
  map<unsigned int, uid_resolution_state*>::iterator uid_iter;
×
208
  for (uid_iter = m_universe_uids.begin(); uid_iter != m_universe_uids.end();
×
209
       uid_iter++) {
×
210
    delete uid_iter->second;
×
211
  }
212
  m_universe_uids.clear();
×
213
}
×
214

215
/**
216
 * @brief Can be called while the server is running. Ownership is not transferred.
217
 */
218
void RDMHTTPModule::SetPidStore(const ola::rdm::RootPidStore *pid_store) {
×
219
  MutexLocker lock(&m_pid_store_mu);
×
220
  m_pid_store = pid_store;
×
221
}
×
222

223

224
/**
225
 * @brief Run RDM discovery for a universe
226
 * @param request the HTTPRequest
227
 * @param response the HTTPResponse
228
 * @returns MHD_NO or MHD_YES
229
 */
230
int RDMHTTPModule::RunRDMDiscovery(const HTTPRequest *request,
×
231
                                   HTTPResponse *response) {
232
  if (request->CheckParameterExists(OladHTTPServer::HELP_PARAMETER)) {
×
233
    return OladHTTPServer::ServeUsage(response,
×
234
                                      "?id=[universe]&amp;incremental=true");
235
  }
236
  unsigned int universe_id;
×
237
  if (!CheckForInvalidId(request, &universe_id)) {
×
238
    return OladHTTPServer::ServeHelpRedirect(response);
×
239
  }
240

241
  string incremental_str = request->GetParameter("incremental");
×
242
  bool incremental = incremental_str == "true";
×
243

244
  m_client->RunDiscovery(
×
245
      universe_id,
246
      incremental ? client::DISCOVERY_INCREMENTAL : client::DISCOVERY_FULL,
247
      NewSingleCallback(this, &RDMHTTPModule::HandleUIDList,
248
                        response, universe_id));
249

250
  return MHD_YES;
×
251
}
×
252

253

254
/**
255
 * @brief Return the list of uids for this universe as json
256
 * @param request the HTTPRequest
257
 * @param response the HTTPResponse
258
 * @returns MHD_NO or MHD_YES
259
 */
260
int RDMHTTPModule::JsonUIDs(const HTTPRequest *request,
×
261
                            HTTPResponse *response) {
262
  if (request->CheckParameterExists(OladHTTPServer::HELP_PARAMETER)) {
×
263
    return OladHTTPServer::ServeUsage(response, "?id=[universe]");
×
264
  }
265
  unsigned int universe_id;
×
266
  if (!CheckForInvalidId(request, &universe_id)) {
×
267
    return OladHTTPServer::ServeHelpRedirect(response);
×
268
  }
269

270
  m_client->RunDiscovery(
×
271
      universe_id,
272
      client::DISCOVERY_CACHED,
273
      NewSingleCallback(this,
274
                        &RDMHTTPModule::HandleUIDList,
275
                        response,
276
                        universe_id));
277
  return MHD_YES;
278
}
279

280

281
/**
282
 * @brief Return the device info for this uid.
283
 * @param request the HTTPRequest
284
 * @param response the HTTPResponse
285
 * @returns MHD_NO or MHD_YES
286
 */
287
int RDMHTTPModule::JsonUIDInfo(const HTTPRequest *request,
×
288
                               HTTPResponse *response) {
289
  if (request->CheckParameterExists(OladHTTPServer::HELP_PARAMETER)) {
×
290
    return OladHTTPServer::ServeUsage(response, "?id=[universe]&amp;uid=[uid]");
×
291
  }
292
  unsigned int universe_id;
×
293
  if (!CheckForInvalidId(request, &universe_id)) {
×
294
    return OladHTTPServer::ServeHelpRedirect(response);
×
295
  }
296

297
  UID *uid = NULL;
×
298
  if (!CheckForInvalidUid(request, &uid)) {
×
299
    return OladHTTPServer::ServeHelpRedirect(response);
×
300
  }
301

302
  string error;
×
303
  bool ok = m_rdm_api.GetDeviceInfo(
×
304
      universe_id,
305
      *uid,
306
      ola::rdm::ROOT_RDM_DEVICE,
307
      NewSingleCallback(this,
308
                        &RDMHTTPModule::UIDInfoHandler,
309
                        response),
310
      &error);
311
  delete uid;
×
312

313
  if (!ok) {
×
314
    return m_server->ServeError(response, BACKEND_DISCONNECTED_ERROR);
×
315
  }
316
  return MHD_YES;
317
}
×
318

319

320
/**
321
 * @brief Returns the identify state for the device.
322
 * @param request the HTTPRequest
323
 * @param response the HTTPResponse
324
 * @returns MHD_NO or MHD_YES
325
 */
326
int RDMHTTPModule::JsonUIDIdentifyDevice(const HTTPRequest *request,
×
327
                                         HTTPResponse *response) {
328
  if (request->CheckParameterExists(OladHTTPServer::HELP_PARAMETER)) {
×
329
    return OladHTTPServer::ServeUsage(response, "?id=[universe]&amp;uid=[uid]");
×
330
  }
331
  unsigned int universe_id;
×
332
  if (!CheckForInvalidId(request, &universe_id)) {
×
333
    return OladHTTPServer::ServeHelpRedirect(response);
×
334
  }
335

336
  UID *uid = NULL;
×
337
  if (!CheckForInvalidUid(request, &uid)) {
×
338
    return OladHTTPServer::ServeHelpRedirect(response);
×
339
  }
340

341
  string error;
×
342
  bool ok = m_rdm_api.GetIdentifyDevice(
×
343
      universe_id,
344
      *uid,
345
      ola::rdm::ROOT_RDM_DEVICE,
346
      NewSingleCallback(this,
347
                        &RDMHTTPModule::UIDIdentifyDeviceHandler,
348
                        response),
349
      &error);
350
  delete uid;
×
351

352
  if (!ok) {
×
353
    return m_server->ServeError(response, BACKEND_DISCONNECTED_ERROR);
×
354
  }
355
  return MHD_YES;
356
}
×
357

358

359
/**
360
 * @brief Returns the personalities on the device
361
 * @param request the HTTPRequest
362
 * @param response the HTTPResponse
363
 * @returns MHD_NO or MHD_YES
364
 */
365
int RDMHTTPModule::JsonUIDPersonalities(const HTTPRequest *request,
×
366
                                        HTTPResponse *response) {
367
  if (request->CheckParameterExists(OladHTTPServer::HELP_PARAMETER)) {
×
368
    return OladHTTPServer::ServeUsage(response, "?id=[universe]&amp;uid=[uid]");
×
369
  }
370
  unsigned int universe_id;
×
371
  if (!CheckForInvalidId(request, &universe_id)) {
×
372
    return OladHTTPServer::ServeHelpRedirect(response);
×
373
  }
374

375
  UID *uid = NULL;
×
376
  if (!CheckForInvalidUid(request, &uid)) {
×
377
    return OladHTTPServer::ServeHelpRedirect(response);
×
378
  }
379

380
  string error = GetPersonalities(request, response, universe_id, *uid, false,
×
381
                                  true);
×
382

383
  delete uid;
×
384
  if (!error.empty()) {
×
385
    return m_server->ServeError(response, BACKEND_DISCONNECTED_ERROR + error);
×
386
  }
387
  return MHD_YES;
388
}
×
389

390

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

410
  UID *uid = NULL;
×
411
  if (!CheckForInvalidUid(request, &uid)) {
×
412
    return OladHTTPServer::ServeHelpRedirect(response);
×
413
  }
414

415
  string error;
×
416
  bool ok = m_rdm_api.GetSupportedParameters(
×
417
      universe_id,
418
      *uid,
419
      ola::rdm::ROOT_RDM_DEVICE,
420
      NewSingleCallback(this,
421
                        &RDMHTTPModule::SupportedParamsHandler,
422
                        response),
423
      &error);
424
  delete uid;
×
425

426
  if (!ok) {
×
427
    return m_server->ServeError(response, BACKEND_DISCONNECTED_ERROR);
×
428
  }
429
  return MHD_YES;
430
}
×
431

432

433
/**
434
 * @brief Return a list of sections to display in the RDM control panel.
435
 *
436
 * We use the response from SUPPORTED_PARAMS and DEVICE_INFO to decide which
437
 * PIDs exist.
438
 * @param request the HTTPRequest
439
 * @param response the HTTPResponse
440
 * @returns MHD_NO or MHD_YES
441
 */
442
int RDMHTTPModule::JsonSupportedSections(const HTTPRequest *request,
×
443
                                         HTTPResponse *response) {
444
  if (request->CheckParameterExists(OladHTTPServer::HELP_PARAMETER)) {
×
445
    return OladHTTPServer::ServeUsage(response, "?id=[universe]&amp;uid=[uid]");
×
446
  }
447

448
  unsigned int universe_id;
×
449
  if (!CheckForInvalidId(request, &universe_id)) {
×
450
    return OladHTTPServer::ServeHelpRedirect(response);
×
451
  }
452

453
  UID *uid = NULL;
×
454
  if (!CheckForInvalidUid(request, &uid)) {
×
455
    return OladHTTPServer::ServeHelpRedirect(response);
×
456
  }
457

458
  string error;
×
459
  bool ok = m_rdm_api.GetSupportedParameters(
×
460
      universe_id,
461
      *uid,
462
      ola::rdm::ROOT_RDM_DEVICE,
463
      NewSingleCallback(this,
×
464
                        &RDMHTTPModule::SupportedSectionsHandler,
465
                        response,
466
                        universe_id,
467
                        *uid),
468
      &error);
469
  delete uid;
×
470

471
  if (!ok) {
×
472
    return m_server->ServeError(response, BACKEND_DISCONNECTED_ERROR);
×
473
  }
474
  return MHD_YES;
475
}
×
476

477

478
/**
479
 * @brief Get the information required to render a section in the RDM
480
 *   controller panel
481
 */
482
int RDMHTTPModule::JsonSectionInfo(const HTTPRequest *request,
×
483
                                   HTTPResponse *response) {
484
  if (request->CheckParameterExists(OladHTTPServer::HELP_PARAMETER)) {
×
485
    return OladHTTPServer::ServeUsage(response, "?id=[universe]&amp;uid=[uid]"
×
486
                                      "&amp;section=[section]<br />See "
487
                                      "/json/rdm/supported_sections for "
488
                                      "sections");
489
  }
490
  unsigned int universe_id;
×
491
  if (!CheckForInvalidId(request, &universe_id)) {
×
492
    return OladHTTPServer::ServeHelpRedirect(response);
×
493
  }
494

495
  UID *uid = NULL;
×
496
  if (!CheckForInvalidUid(request, &uid)) {
×
497
    return OladHTTPServer::ServeHelpRedirect(response);
×
498
  }
499

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

567
  delete uid;
×
568
  if (!error.empty()) {
×
569
    return m_server->ServeError(response, BACKEND_DISCONNECTED_ERROR + error);
×
570
  }
571
  return MHD_YES;
572
}
×
573

574

575
/**
576
 * Save the information for a section or item.
577
 */
578
int RDMHTTPModule::JsonSaveSectionInfo(const HTTPRequest *request,
×
579
                                       HTTPResponse *response) {
580
  if (request->CheckParameterExists(OladHTTPServer::HELP_PARAMETER)) {
×
581
    return OladHTTPServer::ServeUsage(response, "?id=[universe]&amp;uid=[uid]"
×
582
                                      "&amp;section=[section]<br />See "
583
                                      "/json/rdm/supported_sections for "
584
                                      "sections");
585
  }
586
  unsigned int universe_id;
×
587
  if (!CheckForInvalidId(request, &universe_id)) {
×
588
    return OladHTTPServer::ServeHelpRedirect(response);
×
589
  }
590

591
  UID *uid = NULL;
×
592
  if (!CheckForInvalidUid(request, &uid)) {
×
593
    return OladHTTPServer::ServeHelpRedirect(response);
×
594
  }
595

596
  string section_id = request->GetParameter(SECTION_KEY);
×
597
  string error;
×
598
  if (section_id == DEVICE_LABEL_SECTION) {
×
599
    error = SetDeviceLabel(request, response, universe_id, *uid);
×
600
  } else if (section_id == COMMS_STATUS_SECTION) {
×
601
    error = ClearCommsCounters(response, universe_id, *uid);
×
602
  } else if (section_id == FACTORY_DEFAULTS_SECTION) {
×
603
    error = SetFactoryDefault(response, universe_id, *uid);
×
604
  } else if (section_id == LANGUAGE_SECTION) {
×
605
    error = SetLanguage(request, response, universe_id, *uid);
×
606
  } else if (section_id == PERSONALITY_SECTION) {
×
607
    error = SetPersonality(request, response, universe_id, *uid);
×
608
  } else if (section_id == DMX_ADDRESS_SECTION) {
×
609
    error = SetStartAddress(request, response, universe_id, *uid);
×
610
  } else if (section_id == SENSOR_SECTION) {
×
611
    error = RecordSensor(request, response, universe_id, *uid);
×
612
  } else if (section_id == DEVICE_HOURS_SECTION) {
×
613
    error = SetDeviceHours(request, response, universe_id, *uid);
×
614
  } else if (section_id == LAMP_HOURS_SECTION) {
×
615
    error = SetLampHours(request, response, universe_id, *uid);
×
616
  } else if (section_id == LAMP_MODE_SECTION) {
×
617
    error = SetLampMode(request, response, universe_id, *uid);
×
618
  } else if (section_id == LAMP_STATE_SECTION) {
×
619
    error = SetLampState(request, response, universe_id, *uid);
×
620
  } else if (section_id == LAMP_STRIKES_SECTION) {
×
621
    error = SetLampStrikes(request, response, universe_id, *uid);
×
622
  } else if (section_id == POWER_CYCLES_SECTION) {
×
623
    error = SetPowerCycles(request, response, universe_id, *uid);
×
624
  } else if (section_id == DISPLAY_INVERT_SECTION) {
×
625
    error = SetDisplayInvert(request, response, universe_id, *uid);
×
626
  } else if (section_id == DISPLAY_LEVEL_SECTION) {
×
627
    error = SetDisplayLevel(request, response, universe_id, *uid);
×
628
  } else if (section_id == PAN_INVERT_SECTION) {
×
629
    error = SetPanInvert(request, response, universe_id, *uid);
×
630
  } else if (section_id == TILT_INVERT_SECTION) {
×
631
    error = SetTiltInvert(request, response, universe_id, *uid);
×
632
  } else if (section_id == PAN_TILT_SWAP_SECTION) {
×
633
    error = SetPanTiltSwap(request, response, universe_id, *uid);
×
634
  } else if (section_id == CLOCK_SECTION) {
×
635
    error = SyncClock(response, universe_id, *uid);
×
636
  } else if (section_id == IDENTIFY_DEVICE_SECTION) {
×
637
    error = SetIdentifyDevice(request, response, universe_id, *uid);
×
638
  } else if (section_id == POWER_STATE_SECTION) {
×
639
    error = SetPowerState(request, response, universe_id, *uid);
×
640
  } else if (section_id == RESET_DEVICE_SECTION) {
×
641
    error = SetResetDevice(request, response, universe_id, *uid);
×
642
  } else if (section_id == DNS_HOSTNAME_SECTION) {
×
643
    error = SetDnsHostname(request, response, universe_id, *uid);
×
644
  } else if (section_id == DNS_DOMAIN_NAME_SECTION) {
×
645
    error = SetDnsDomainName(request, response, universe_id, *uid);
×
646
  } else {
647
    OLA_INFO << "Missing or unknown section id: " << section_id;
×
648
    delete uid;
×
649
    return OladHTTPServer::ServeHelpRedirect(response);
×
650
  }
651

652
  delete uid;
×
653
  if (!error.empty()) {
×
654
    return RespondWithError(response, error);
×
655
  }
656
  return MHD_YES;
657
}
×
658

659

660
/**
661
 * This is called from the main http server whenever a new list of active
662
 * universes is received. It's used to prune the uid map so we don't bother
663
 * trying to resolve uids for universes that no longer exist.
664
 */
665
void RDMHTTPModule::PruneUniverseList(const vector<OlaUniverse> &universes) {
×
666
  map<unsigned int, uid_resolution_state*>::iterator uid_iter;
×
667
  for (uid_iter = m_universe_uids.begin(); uid_iter != m_universe_uids.end();
×
668
       uid_iter++) {
×
669
    uid_iter->second->active = false;
×
670
  }
671

672
  vector<OlaUniverse>::const_iterator iter;
×
673
  for (iter = universes.begin(); iter != universes.end(); ++iter) {
×
674
    uid_iter = m_universe_uids.find(iter->Id());
×
675
    if (uid_iter != m_universe_uids.end()) {
×
676
      uid_iter->second->active = true;
×
677
    }
678
  }
679

680
  // clean up the uid map for those universes that no longer exist
681
  for (uid_iter = m_universe_uids.begin(); uid_iter != m_universe_uids.end();) {
×
682
    if (!uid_iter->second->active) {
×
683
      OLA_DEBUG << "removing " << uid_iter->first << " from the uid map";
×
684
      delete uid_iter->second;
×
685
      m_universe_uids.erase(uid_iter++);
×
686
    } else {
687
      uid_iter++;
×
688
    }
689
  }
690
}
×
691

692

693
/*
694
 * @brief Handle the UID list response.
695
 * @param response the HTTPResponse that is associated with the request.
696
 * @param uids the UIDs for this response.
697
 * @param error an error string.
698
 */
699
void RDMHTTPModule::HandleUIDList(HTTPResponse *response,
×
700
                                  unsigned int universe_id,
701
                                  const Result &result,
702
                                  const ola::rdm::UIDSet &uids) {
703
  if (!result.Success()) {
×
704
    m_server->ServeError(response, result.Error());
×
705
    return;
×
706
  }
707
  ola::rdm::UIDSet::Iterator iter = uids.Begin();
×
708
  uid_resolution_state *uid_state = GetUniverseUidsOrCreate(universe_id);
×
709

710
  // mark all uids as inactive so we can remove the unused ones at the end
711
  map<UID, resolved_uid>::iterator uid_iter;
×
712
  for (uid_iter = uid_state->resolved_uids.begin();
×
713
       uid_iter != uid_state->resolved_uids.end(); ++uid_iter)
×
714
    uid_iter->second.active = false;
×
715

716
  JsonObject json;
×
717
  json.Add("universe", universe_id);
×
718
  JsonArray *json_uids = json.AddArray("uids");
×
719

720
  for (; iter != uids.End(); ++iter) {
×
721
    uid_iter = uid_state->resolved_uids.find(*iter);
×
722

723
    string manufacturer = "";
×
724
    string device = "";
×
725

726
    if (uid_iter == uid_state->resolved_uids.end()) {
×
727
      // schedule resolution
728
      uid_state->pending_uids.push(std::make_pair(*iter, RESOLVE_MANUFACTURER));
×
729
      uid_state->pending_uids.push(std::make_pair(*iter, RESOLVE_DEVICE));
×
730
      resolved_uid uid_descriptor = {"", "", true};
×
731
      uid_state->resolved_uids[*iter] = uid_descriptor;
×
732
      OLA_INFO << "Adding UID " << *iter << " to resolution queue";
×
733
    } else {
×
734
      manufacturer = uid_iter->second.manufacturer;
×
735
      device = uid_iter->second.device;
×
736
      uid_iter->second.active = true;
×
737
    }
738

739
    JsonObject *json_uid = json_uids->AppendObject();
×
740
    json_uid->Add("manufacturer_id", iter->ManufacturerId());
×
741
    json_uid->Add("device_id", iter->DeviceId());
×
742
    json_uid->Add("device", device);
×
743
    json_uid->Add("manufacturer", manufacturer);
×
744
    json_uid->Add("uid", iter->ToString());
×
745
  }
×
746

747
  response->SetNoCache();
×
748
  response->SetContentType(HTTPServer::CONTENT_TYPE_PLAIN);
×
749
  response->SendJson(json);
×
750
  delete response;
×
751

752
  // remove any old UIDs
753
  for (uid_iter = uid_state->resolved_uids.begin();
×
754
       uid_iter != uid_state->resolved_uids.end();) {
×
755
    if (!uid_iter->second.active) {
×
756
      OLA_INFO << "Removed UID " << uid_iter->first;
×
757
      uid_state->resolved_uids.erase(uid_iter++);
×
758
    } else {
759
      ++uid_iter;
×
760
    }
761
  }
762

763
  if (!uid_state->uid_resolution_running) {
×
764
    ResolveNextUID(universe_id);
×
765
  }
766
}
×
767

768

769
/*
770
 * @brief Send the RDM command needed to resolve the next uid in the queue
771
 * @param universe_id the universe id to resolve the next UID for.
772
 */
773
void RDMHTTPModule::ResolveNextUID(unsigned int universe_id) {
×
774
  bool sent_request = false;
×
775
  string error;
×
776
  uid_resolution_state *uid_state = GetUniverseUids(universe_id);
×
777

778
  if (!uid_state) {
×
779
    return;
780
  }
781

782
  while (!sent_request) {
×
783
    if (uid_state->pending_uids.empty()) {
×
784
      uid_state->uid_resolution_running = false;
×
785
      return;
×
786
    }
787
    uid_state->uid_resolution_running = true;
×
788

789
    pair<UID, uid_resolve_action> &uid_action_pair =
×
790
      uid_state->pending_uids.front();
×
791
    if (uid_action_pair.second == RESOLVE_MANUFACTURER) {
×
792
      OLA_INFO << "sending manufacturer request for " << uid_action_pair.first;
×
793
      sent_request = m_rdm_api.GetManufacturerLabel(
×
794
          universe_id,
795
          uid_action_pair.first,
×
796
          ola::rdm::ROOT_RDM_DEVICE,
797
          NewSingleCallback(this,
×
798
                            &RDMHTTPModule::UpdateUIDManufacturerLabel,
799
                            universe_id,
800
                            uid_action_pair.first),
×
801
          &error);
802
      uid_state->pending_uids.pop();
×
803
    } else if (uid_action_pair.second == RESOLVE_DEVICE) {
×
804
      OLA_INFO << "sending device request for " << uid_action_pair.first;
×
805
      sent_request = m_rdm_api.GetDeviceLabel(
×
806
          universe_id,
807
          uid_action_pair.first,
×
808
          ola::rdm::ROOT_RDM_DEVICE,
809
          NewSingleCallback(this,
×
810
                            &RDMHTTPModule::UpdateUIDDeviceLabel,
811
                            universe_id,
812
                            uid_action_pair.first),
×
813
          &error);
814
      uid_state->pending_uids.pop();
×
815
    } else {
816
      OLA_WARN << "Unknown UID resolve action " <<
×
817
        static_cast<int>(uid_action_pair.second);
×
818
    }
819
  }
820
}
×
821

822
/*
823
 * @brief Handle the manufacturer label response.
824
 */
825
void RDMHTTPModule::UpdateUIDManufacturerLabel(
×
826
    unsigned int universe,
827
    UID uid,
828
    const ola::rdm::ResponseStatus &status,
829
    const string &manufacturer_label) {
830
  uid_resolution_state *uid_state = GetUniverseUids(universe);
×
831

832
  if (!uid_state) {
×
833
    return;
834
  }
835

836
  if (CheckForRDMSuccess(status)) {
×
837
    map<UID, resolved_uid>::iterator uid_iter;
×
838
    uid_iter = uid_state->resolved_uids.find(uid);
×
839
    if (uid_iter != uid_state->resolved_uids.end()) {
×
840
      uid_iter->second.manufacturer = manufacturer_label;
×
841
    }
842
  }
843
  ResolveNextUID(universe);
×
844
}
845

846

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

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

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

871

872
/*
873
 * @brief Get the UID resolution state for a particular universe
874
 * @param universe the id of the universe to get the state for
875
 */
876
RDMHTTPModule::uid_resolution_state *RDMHTTPModule::GetUniverseUids(
×
877
    unsigned int universe) {
878
  map<unsigned int, uid_resolution_state*>::iterator iter =
×
879
    m_universe_uids.find(universe);
×
880
  return iter == m_universe_uids.end() ? NULL : iter->second;
×
881
}
882

883

884
/*
885
 * @brief Get the UID resolution state for a particular universe or create one if it
886
 * doesn't exist.
887
 * @param universe the id of the universe to get the state for
888
 */
889
RDMHTTPModule::uid_resolution_state *RDMHTTPModule::GetUniverseUidsOrCreate(
×
890
    unsigned int universe) {
891
  map<unsigned int, uid_resolution_state*>::iterator iter =
×
892
    m_universe_uids.find(universe);
×
893

894
  if (iter == m_universe_uids.end()) {
×
895
    OLA_DEBUG << "Adding a new state entry for " << universe;
×
896
    uid_resolution_state *state  = new uid_resolution_state();
×
897
    state->uid_resolution_running = false;
×
898
    state->active = true;
×
899
    pair<unsigned int, uid_resolution_state*> p(universe, state);
×
900
    iter = m_universe_uids.insert(p).first;
×
901
  }
902
  return iter->second;
×
903
}
904

905

906
/**
907
 * @brief Handle the Device Info response and build the JSON
908
 */
909
void RDMHTTPModule::UIDInfoHandler(HTTPResponse *response,
×
910
                                   const ola::rdm::ResponseStatus &status,
911
                                   const ola::rdm::DeviceDescriptor &device) {
912
  if (CheckForRDMError(response, status)) {
×
913
    return;
×
914
  }
915

916
  JsonObject json;
×
917
  json.Add("error", "");
×
918
  json.Add("address", device.dmx_start_address);
×
919
  json.Add("footprint", device.dmx_footprint);
×
920
  json.Add("personality", static_cast<int>(device.current_personality));
×
921
  json.Add("personality_count", static_cast<int>(device.personality_count));
×
922

923
  response->SetNoCache();
×
924
  response->SetContentType(HTTPServer::CONTENT_TYPE_PLAIN);
×
925
  response->SendJson(json);
×
926
  delete response;
×
927
}
×
928

929

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

941
  JsonObject json;
×
942
  json.Add("error", "");
×
943
  json.Add("identify_device", value);
×
944

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

951

952
/**
953
 * @brief Send the response to a DMX personality section
954
 */
955
void RDMHTTPModule::SendPersonalityResponse(HTTPResponse *response,
×
956
                                            personality_info *info) {
957
  JsonObject json;
×
958
  json.Add("error", "");
×
959
  JsonArray *personalities = json.AddArray("personalities");
×
960

961
  unsigned int i = 1;
×
962
  while (i <= info->total && i <= info->personalities.size()) {
×
963
    if (info->personalities[i - 1].first != INVALID_PERSONALITY) {
×
964
      JsonObject *personality = personalities->AppendObject();
×
965
      personality->Add("name", info->personalities[i - 1].second);
×
966
      personality->Add("index", i);
×
967
      personality->Add("footprint", info->personalities[i - 1].first);
×
968
    }
969
    i++;
×
970
  }
971
  json.Add("selected", info->active);
×
972

973
  response->SetNoCache();
×
974
  response->SetContentType(HTTPServer::CONTENT_TYPE_PLAIN);
×
975
  response->SendJson(json);
×
976
  delete info->uid;
×
977
  delete info;
×
978
}
×
979

980

981
/*
982
 * @brief Handle the response from a supported params request
983
 */
984
void RDMHTTPModule::SupportedParamsHandler(
×
985
    HTTPResponse *response,
986
    const ola::rdm::ResponseStatus &status,
987
    const vector<uint16_t> &pids) {
988
  JsonObject json;
×
989
  if (CheckForRDMSuccess(status)) {
×
990
    JsonArray *pids_json = json.AddArray("pids");
×
991
    vector<uint16_t>::const_iterator iter = pids.begin();
×
992
    for (; iter != pids.end(); ++iter)
×
993
      pids_json->Append(*iter);
×
994
  }
995

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

1002

1003
/**
1004
 * @brief Takes the supported PIDs for a device and come up with the list of
1005
 * sections to display in the RDM panel
1006
 */
1007
void RDMHTTPModule::SupportedSectionsHandler(
×
1008
    HTTPResponse *response,
1009
    unsigned int universe_id,
1010
    UID uid,
1011
    const ola::rdm::ResponseStatus &status,
1012
    const vector<uint16_t> &pid_list) {
1013
  string error;
×
1014

1015
  // nacks here are ok if the device doesn't support SUPPORTED_PARAMS
1016
  if (!CheckForRDMSuccess(status) && !status.WasNacked()) {
×
1017
    m_server->ServeError(response, BACKEND_DISCONNECTED_ERROR + error);
×
1018
    return;
×
1019
  }
1020

1021
  m_rdm_api.GetDeviceInfo(
×
1022
      universe_id,
1023
      uid,
1024
      ola::rdm::ROOT_RDM_DEVICE,
1025
      NewSingleCallback(this,
×
1026
                        &RDMHTTPModule::SupportedSectionsDeviceInfoHandler,
1027
                        response,
1028
                        pid_list),
1029
      &error);
1030
  if (!error.empty())
×
1031
    m_server->ServeError(response, BACKEND_DISCONNECTED_ERROR + error);
×
1032
}
×
1033

1034

1035
/**
1036
 * @brief Handle the second part of the supported sections request.
1037
 */
1038
void RDMHTTPModule::SupportedSectionsDeviceInfoHandler(
×
1039
    HTTPResponse *response,
1040
    const vector<uint16_t> pid_list,
1041
    const ola::rdm::ResponseStatus &status,
1042
    const ola::rdm::DeviceDescriptor &device) {
1043
  vector<section_info> sections;
×
1044
  std::set<uint16_t> pids;
×
1045
  copy(pid_list.begin(), pid_list.end(), inserter(pids, pids.end()));
×
1046

1047
  // PID_DEVICE_INFO is required so we always add it
1048
  string hint;
×
1049
  if (pids.find(ola::rdm::PID_DEVICE_MODEL_DESCRIPTION) != pids.end()) {
×
1050
      hint.push_back('m');  // m is for device model
×
1051
  }
1052

1053
  AddSection(&sections, DEVICE_INFO_SECTION, DEVICE_INFO_SECTION_NAME, hint);
×
1054

1055
  AddSection(&sections, IDENTIFY_DEVICE_SECTION, IDENTIFY_DEVICE_SECTION_NAME);
×
1056

1057
  bool dmx_address_added = false;
×
1058
  bool include_software_version = false;
×
1059
  set<uint16_t>::const_iterator iter = pids.begin();
×
1060
  for (; iter != pids.end(); ++iter) {
×
1061
    switch (*iter) {
×
1062
      case ola::rdm::PID_PROXIED_DEVICES:
×
1063
        AddSection(&sections, PROXIED_DEVICES_SECTION,
×
1064
                   PROXIED_DEVICES_SECTION_NAME);
1065
        break;
×
1066
      case ola::rdm::PID_COMMS_STATUS:
×
1067
        AddSection(&sections, COMMS_STATUS_SECTION, COMMS_STATUS_SECTION_NAME);
×
1068
        break;
×
1069
      case ola::rdm::PID_PRODUCT_DETAIL_ID_LIST:
×
1070
        AddSection(&sections, PRODUCT_DETAIL_SECTION,
×
1071
                   PRODUCT_DETAIL_SECTION_NAME);
1072
        break;
×
1073
      case ola::rdm::PID_MANUFACTURER_LABEL:
×
1074
        AddSection(&sections, MANUFACTURER_LABEL_SECTION,
×
1075
                   MANUFACTURER_LABEL_SECTION_NAME);
1076
        break;
×
1077
      case ola::rdm::PID_DEVICE_LABEL:
×
1078
        AddSection(&sections, DEVICE_LABEL_SECTION, DEVICE_LABEL_SECTION_NAME);
×
1079
        break;
×
1080
      case ola::rdm::PID_FACTORY_DEFAULTS:
×
1081
        AddSection(&sections, FACTORY_DEFAULTS_SECTION,
×
1082
                   FACTORY_DEFAULTS_SECTION_NAME);
1083
        break;
×
1084
      case ola::rdm::PID_LANGUAGE:
×
1085
        AddSection(&sections, LANGUAGE_SECTION, LANGUAGE_SECTION_NAME);
×
1086
        break;
×
1087
      case ola::rdm::PID_BOOT_SOFTWARE_VERSION_ID:
1088
      case ola::rdm::PID_BOOT_SOFTWARE_VERSION_LABEL:
1089
        include_software_version = true;
×
1090
        break;
1091
      case ola::rdm::PID_DMX_PERSONALITY:
×
1092
        if (pids.find(ola::rdm::PID_DMX_PERSONALITY_DESCRIPTION) ==
×
1093
            pids.end()) {
×
1094
          AddSection(&sections, PERSONALITY_SECTION, PERSONALITY_SECTION_NAME);
×
1095
        } else {
1096
          AddSection(&sections, PERSONALITY_SECTION, PERSONALITY_SECTION_NAME,
×
1097
                     "l");
1098
        }
1099
        break;
1100
      case ola::rdm::PID_DMX_START_ADDRESS:
×
1101
        AddSection(&sections, DMX_ADDRESS_SECTION, DMX_ADDRESS_SECTION_NAME);
×
1102
        dmx_address_added = true;
×
1103
        break;
×
1104
      case ola::rdm::PID_DEVICE_HOURS:
×
1105
        AddSection(&sections, DEVICE_HOURS_SECTION, DEVICE_HOURS_SECTION_NAME);
×
1106
        break;
×
1107
      case ola::rdm::PID_LAMP_HOURS:
×
1108
        AddSection(&sections, LAMP_HOURS_SECTION, LAMP_HOURS_SECTION_NAME);
×
1109
        break;
×
1110
      case ola::rdm::PID_LAMP_STRIKES:
×
1111
        AddSection(&sections, LAMP_STRIKES_SECTION, LAMP_STRIKES_SECTION_NAME);
×
1112
        break;
×
1113
      case ola::rdm::PID_LAMP_STATE:
×
1114
        AddSection(&sections, LAMP_STATE_SECTION, LAMP_STATE_SECTION_NAME);
×
1115
        break;
×
1116
      case ola::rdm::PID_LAMP_ON_MODE:
×
1117
        AddSection(&sections, LAMP_MODE_SECTION, LAMP_MODE_SECTION_NAME);
×
1118
        break;
×
1119
      case ola::rdm::PID_DEVICE_POWER_CYCLES:
×
1120
        AddSection(&sections, POWER_CYCLES_SECTION, POWER_CYCLES_SECTION_NAME);
×
1121
        break;
×
1122
      case ola::rdm::PID_DISPLAY_INVERT:
×
1123
        AddSection(&sections, DISPLAY_INVERT_SECTION,
×
1124
                   DISPLAY_INVERT_SECTION_NAME);
1125
        break;
×
1126
      case ola::rdm::PID_DISPLAY_LEVEL:
×
1127
        AddSection(&sections, DISPLAY_LEVEL_SECTION,
×
1128
                   DISPLAY_LEVEL_SECTION_NAME);
1129
        break;
×
1130
      case ola::rdm::PID_PAN_INVERT:
×
1131
        AddSection(&sections, PAN_INVERT_SECTION, PAN_INVERT_SECTION_NAME);
×
1132
        break;
×
1133
      case ola::rdm::PID_TILT_INVERT:
×
1134
        AddSection(&sections, TILT_INVERT_SECTION, TILT_INVERT_SECTION_NAME);
×
1135
        break;
×
1136
      case ola::rdm::PID_PAN_TILT_SWAP:
×
1137
        AddSection(&sections, PAN_TILT_SWAP_SECTION,
×
1138
                   PAN_TILT_SWAP_SECTION_NAME);
1139
        break;
×
1140
      case ola::rdm::PID_REAL_TIME_CLOCK:
×
1141
        AddSection(&sections, CLOCK_SECTION, CLOCK_SECTION_NAME);
×
1142
        break;
×
1143
      case ola::rdm::PID_POWER_STATE:
×
1144
        AddSection(&sections, POWER_STATE_SECTION, POWER_STATE_SECTION_NAME);
×
1145
        break;
×
1146
      case ola::rdm::PID_RESET_DEVICE:
×
1147
        AddSection(&sections, RESET_DEVICE_SECTION, RESET_DEVICE_SECTION_NAME);
×
1148
        break;
×
1149
      case ola::rdm::PID_DNS_HOSTNAME:
×
1150
        AddSection(&sections, DNS_HOSTNAME_SECTION, DNS_HOSTNAME_SECTION_NAME);
×
1151
        break;
×
1152
      case ola::rdm::PID_DNS_DOMAIN_NAME:
×
1153
        AddSection(&sections,
×
1154
                   DNS_DOMAIN_NAME_SECTION,
1155
                   DNS_DOMAIN_NAME_SECTION_NAME);
1156
        break;
×
1157
    }
1158
  }
1159

1160
  if (include_software_version) {
×
1161
    AddSection(&sections, BOOT_SOFTWARE_SECTION, BOOT_SOFTWARE_SECTION_NAME);
×
1162
  }
1163

1164
  if (CheckForRDMSuccess(status)) {
×
1165
    if (device.dmx_footprint && !dmx_address_added) {
×
1166
      AddSection(&sections, DMX_ADDRESS_SECTION, DMX_ADDRESS_SECTION_NAME);
×
1167
    }
1168
    if (device.sensor_count &&
×
1169
        pids.find(ola::rdm::PID_SENSOR_DEFINITION) != pids.end() &&
×
1170
        pids.find(ola::rdm::PID_SENSOR_VALUE) != pids.end()) {
×
1171
      // sensors count from 1
1172
      for (unsigned int i = 0; i < device.sensor_count; ++i) {
×
1173
        ostringstream heading, hint;
×
1174
        hint << i;
×
1175
        heading << "Sensor " << std::setfill(' ') << std::setw(3) << i;
×
1176
        AddSection(&sections, SENSOR_SECTION, heading.str(), hint.str());
×
1177
      }
×
1178
    }
1179
  }
1180

1181
  sort(sections.begin(), sections.end(), lt_section_info());
×
1182

1183
  JsonArray json;
×
1184
  vector<section_info>::const_iterator section_iter = sections.begin();
×
1185
  for (; section_iter != sections.end(); ++section_iter) {
×
1186
    JsonObject *json_obj = json.AppendObject();
×
1187
    json_obj->Add("id", section_iter->id);
×
1188
    json_obj->Add("name", section_iter->name);
×
1189
    json_obj->Add("hint",  section_iter->hint);
×
1190
  }
1191

1192
  response->SetNoCache();
×
1193
  response->SetContentType(HTTPServer::CONTENT_TYPE_PLAIN);
×
1194
  response->SendJson(json);
×
1195
  delete response;
×
1196
}
×
1197

1198

1199
/*
1200
 * @brief Handle the request for the communication status.
1201
 */
1202
string RDMHTTPModule::GetCommStatus(HTTPResponse *response,
×
1203
                                    unsigned int universe_id,
1204
                                    const UID &uid) {
1205
  string error;
×
1206
  m_rdm_api.GetCommStatus(
×
1207
    universe_id,
1208
    uid,
1209
    NewSingleCallback(this,
1210
                      &RDMHTTPModule::CommStatusHandler,
1211
                      response),
1212
    &error);
1213
  return error;
×
1214
}
×
1215

1216

1217
/**
1218
 * @brief Handle the response to a communication status call
1219
 */
1220
void RDMHTTPModule::CommStatusHandler(HTTPResponse *response,
×
1221
                                      const ola::rdm::ResponseStatus &status,
1222
                                      uint16_t short_messages,
1223
                                      uint16_t length_mismatch,
1224
                                      uint16_t checksum_fail) {
1225
  if (CheckForRDMError(response, status)) {
×
1226
    return;
×
1227
  }
1228
  JsonSection section;
×
1229

1230
  section.AddItem(new UIntItem("Short Messages", short_messages));
×
1231
  section.AddItem(new UIntItem("Length Mismatch", length_mismatch));
×
1232
  section.AddItem(new UIntItem("Checksum Failures", checksum_fail));
×
1233
  section.AddItem(new HiddenItem("1", GENERIC_UINT_FIELD));
×
1234
  section.SetSaveButton("Clear Counters");
×
1235
  RespondWithSection(response, section);
×
1236
}
×
1237

1238

1239
/**
1240
 * @brief Clear the communication status counters
1241
 */
1242
string RDMHTTPModule::ClearCommsCounters(HTTPResponse *response,
×
1243
                                         unsigned int universe_id,
1244
                                         const UID &uid) {
1245
  string error;
×
1246
  m_rdm_api.ClearCommStatus(
×
1247
      universe_id,
1248
      uid,
1249
      NewSingleCallback(this,
1250
                        &RDMHTTPModule::SetHandler,
1251
                        response),
1252
      &error);
1253
  return error;
×
1254
}
×
1255

1256

1257
/*
1258
 * @brief Handle the request for the proxied devices
1259
 */
1260
string RDMHTTPModule::GetProxiedDevices(HTTPResponse *response,
×
1261
                                        unsigned int universe_id,
1262
                                        const UID &uid) {
1263
  string error;
×
1264
  m_rdm_api.GetProxiedDevices(
×
1265
    universe_id,
1266
    uid,
1267
    NewSingleCallback(this,
1268
                      &RDMHTTPModule::ProxiedDevicesHandler,
1269
                      response,
1270
                      universe_id),
1271
    &error);
1272
  return error;
×
1273
}
×
1274

1275

1276
/**
1277
 * @brief Handle the response to a proxied devices call.
1278
 */
1279
void RDMHTTPModule::ProxiedDevicesHandler(
×
1280
    HTTPResponse *response,
1281
    unsigned int universe_id,
1282
    const ola::rdm::ResponseStatus &status,
1283
    const vector<UID> &uids) {
1284
  if (CheckForRDMError(response, status)) {
×
1285
    return;
×
1286
  }
1287
  JsonSection section;
×
1288

1289
  uid_resolution_state *uid_state = GetUniverseUids(universe_id);
×
1290
  vector<UID>::const_iterator iter = uids.begin();
×
1291
  unsigned int i = 1;
×
1292
  for (; iter != uids.end(); ++iter, ++i) {
×
1293
    string uid = iter->ToString();
×
1294

1295
    // attempt to add device & manufacturer names
1296
    if (uid_state) {
×
1297
      map<UID, resolved_uid>::iterator uid_iter =
×
1298
        uid_state->resolved_uids.find(*iter);
×
1299

1300
      if (uid_iter != uid_state->resolved_uids.end()) {
×
1301
        string device = uid_iter->second.device;
×
1302
        string manufacturer = uid_iter->second.manufacturer;
×
1303

1304
        if (!(device.empty() && manufacturer.empty())) {
×
1305
          ostringstream str;
×
1306
          str << uid_iter->second.manufacturer;
×
1307
          if ((!device.empty()) && (!manufacturer.empty())) {
×
1308
            str << ", ";
×
1309
          }
1310
          str << uid_iter->second.device;
×
1311
          str << " [";
×
1312
          str << iter->ToString();
×
1313
          str << "]";
×
1314
          uid = str.str();
×
1315
        }
×
1316
      }
×
1317
    }
1318
    section.AddItem(new StringItem("Device " + IntToString(i), uid));
×
1319
  }
×
1320
  RespondWithSection(response, section);
×
1321
}
×
1322

1323

1324
/*
1325
 * @brief Handle the request for the device info section.
1326
 */
1327
string RDMHTTPModule::GetDeviceInfo(const HTTPRequest *request,
×
1328
                                    HTTPResponse *response,
1329
                                    unsigned int universe_id,
1330
                                    const UID &uid) {
1331
  string hint = request->GetParameter(HINT_KEY);
×
1332
  string error;
×
1333
  device_info dev_info = {universe_id, uid, hint, "", ""};
×
1334

1335
  m_rdm_api.GetSoftwareVersionLabel(
×
1336
    universe_id,
1337
    uid,
1338
    ola::rdm::ROOT_RDM_DEVICE,
1339
    NewSingleCallback(this,
×
1340
                      &RDMHTTPModule::GetSoftwareVersionHandler,
1341
                      response,
1342
                      dev_info),
1343
    &error);
1344
  return error;
×
1345
}
×
1346

1347

1348
/**
1349
 * @brief Handle the response to a software version call.
1350
 */
1351
void RDMHTTPModule::GetSoftwareVersionHandler(
×
1352
    HTTPResponse *response,
1353
    device_info dev_info,
1354
    const ola::rdm::ResponseStatus &status,
1355
    const string &software_version) {
1356
  string error;
×
1357

1358
  if (CheckForRDMSuccess(status)) {
×
1359
    dev_info.software_version = software_version;
×
1360
  }
1361

1362
  if (dev_info.hint.find('m') != string::npos) {
×
1363
    m_rdm_api.GetDeviceModelDescription(
×
1364
        dev_info.universe_id,
1365
        dev_info.uid,
×
1366
        ola::rdm::ROOT_RDM_DEVICE,
1367
        NewSingleCallback(this,
×
1368
                          &RDMHTTPModule::GetDeviceModelHandler,
1369
                          response,
1370
                          dev_info),
1371
        &error);
1372
  } else {
1373
    m_rdm_api.GetDeviceInfo(
×
1374
        dev_info.universe_id,
1375
        dev_info.uid,
×
1376
        ola::rdm::ROOT_RDM_DEVICE,
1377
        NewSingleCallback(this,
×
1378
                          &RDMHTTPModule::GetDeviceInfoHandler,
1379
                          response,
1380
                          dev_info),
1381
        &error);
1382
  }
1383

1384
  if (!error.empty()) {
×
1385
    m_server->ServeError(response, BACKEND_DISCONNECTED_ERROR + error);
×
1386
  }
1387
}
×
1388

1389

1390
/**
1391
 * @brief Handle the response to a device model call.
1392
 */
1393
void RDMHTTPModule::GetDeviceModelHandler(
×
1394
    HTTPResponse *response,
1395
    device_info dev_info,
1396
    const ola::rdm::ResponseStatus &status,
1397
    const string &device_model) {
1398
  string error;
×
1399

1400
  if (CheckForRDMSuccess(status)) {
×
1401
    dev_info.device_model = device_model;
×
1402
  }
1403

1404
  m_rdm_api.GetDeviceInfo(
×
1405
      dev_info.universe_id,
1406
      dev_info.uid,
×
1407
      ola::rdm::ROOT_RDM_DEVICE,
1408
      NewSingleCallback(this,
×
1409
                        &RDMHTTPModule::GetDeviceInfoHandler,
1410
                        response,
1411
                        dev_info),
1412
      &error);
1413

1414
  if (!error.empty()) {
×
1415
    m_server->ServeError(response, BACKEND_DISCONNECTED_ERROR + error);
×
1416
  }
1417
}
×
1418

1419

1420
/**
1421
 * @brief Handle the response to a device info call and build the response
1422
 */
1423
void RDMHTTPModule::GetDeviceInfoHandler(
×
1424
    HTTPResponse *response,
1425
    device_info dev_info,
1426
    const ola::rdm::ResponseStatus &status,
1427
    const ola::rdm::DeviceDescriptor &device) {
1428
  JsonSection section;
×
1429

1430
  if (CheckForRDMError(response, status)) {
×
1431
    return;
×
1432
  }
1433

1434
  ostringstream stream;
×
1435
  stream << static_cast<int>(device.protocol_version_high) << "."
×
1436
         << static_cast<int>(device.protocol_version_low);
×
1437
  section.AddItem(new StringItem("Protocol Version", stream.str()));
×
1438

1439
  stream.str("");
×
1440
  if (dev_info.device_model.empty()) {
×
1441
    stream << device.device_model;
×
1442
  } else {
1443
    stream << dev_info.device_model << " (" << device.device_model << ")";
×
1444
  }
1445
  section.AddItem(new StringItem("Device Model", stream.str()));
×
1446

1447
  section.AddItem(new StringItem(
×
1448
      "Product Category",
1449
      ola::rdm::ProductCategoryToString(device.product_category)));
×
1450
  stream.str("");
×
1451
  if (dev_info.software_version.empty()) {
×
1452
    stream << device.software_version;
×
1453
  } else {
1454
    stream << dev_info.software_version << " (" << device.software_version
×
1455
           << ")";
×
1456
  }
1457
  section.AddItem(new StringItem("Software Version", stream.str()));
×
1458

1459
  if (device.dmx_start_address == ola::rdm::ZERO_FOOTPRINT_DMX_ADDRESS) {
×
1460
    section.AddItem(new StringItem("DMX Address", "N/A"));
×
1461
  } else {
1462
    section.AddItem(new UIntItem("DMX Address", device.dmx_start_address));
×
1463
  }
1464

1465
  section.AddItem(new UIntItem("DMX Footprint", device.dmx_footprint));
×
1466

1467
  stream.str("");
×
1468
  stream << static_cast<int>(device.current_personality) << " of "
×
1469
         << static_cast<int>(device.personality_count);
×
1470
  section.AddItem(new StringItem("Personality", stream.str()));
×
1471

1472
  section.AddItem(new UIntItem("Sub Devices", device.sub_device_count));
×
1473
  section.AddItem(new UIntItem("Sensors", device.sensor_count));
×
1474
  section.AddItem(new StringItem("UID", dev_info.uid.ToString()));
×
1475
  RespondWithSection(response, section);
×
1476
}
×
1477

1478

1479
/*
1480
 * @brief Handle the request for the product details ids.
1481
 */
1482
string RDMHTTPModule::GetProductIds(OLA_UNUSED const HTTPRequest *request,
×
1483
                                    HTTPResponse *response,
1484
                                    unsigned int universe_id,
1485
                                    const UID &uid) {
1486
  string error;
×
1487
  m_rdm_api.GetProductDetailIdList(
×
1488
      universe_id,
1489
      uid,
1490
      ola::rdm::ROOT_RDM_DEVICE,
1491
      NewSingleCallback(this,
1492
                        &RDMHTTPModule::GetProductIdsHandler,
1493
                        response),
1494
      &error);
1495
  return error;
×
1496
}
×
1497

1498

1499
/**
1500
 * @brief Handle the response to a product detail ids call and build the response.
1501
 */
1502
void RDMHTTPModule::GetProductIdsHandler(
×
1503
    HTTPResponse *response,
1504
    const ola::rdm::ResponseStatus &status,
1505
    const vector<uint16_t> &ids) {
1506
  if (CheckForRDMError(response, status)) {
×
1507
    return;
×
1508
  }
1509

1510
  bool first = true;
×
1511
  ostringstream product_ids;
×
1512
  JsonSection section;
×
1513
  vector<uint16_t>::const_iterator iter = ids.begin();
×
1514
  for (; iter != ids.end(); ++iter) {
×
1515
    string product_id = ola::rdm::ProductDetailToString(*iter);
×
1516
    if (product_id.empty()) {
×
1517
      continue;
×
1518
    }
1519

1520
    if (first) {
×
1521
      first = false;
1522
    } else {
1523
      product_ids << ", ";
×
1524
    }
1525
    product_ids << product_id;
×
1526
  }
×
1527
  section.AddItem(new StringItem("Product Detail IDs", product_ids.str()));
×
1528
  RespondWithSection(response, section);
×
1529
}
×
1530

1531

1532
/**
1533
 * @brief Handle the request for the Manufacturer label.
1534
 */
1535
string RDMHTTPModule::GetManufacturerLabel(
×
1536
    OLA_UNUSED const HTTPRequest *request,
1537
    HTTPResponse *response,
1538
    unsigned int universe_id,
1539
    const UID &uid) {
1540
  string error;
×
1541
  m_rdm_api.GetManufacturerLabel(
×
1542
      universe_id,
1543
      uid,
1544
      ola::rdm::ROOT_RDM_DEVICE,
1545
      NewSingleCallback(this,
×
1546
                        &RDMHTTPModule::GetManufacturerLabelHandler,
1547
                        response,
1548
                        universe_id,
1549
                        uid),
1550
      &error);
1551
  return error;
×
1552
}
×
1553

1554

1555
/**
1556
 * @brief Handle the response to a manufacturer label call and build the response
1557
 */
1558
void RDMHTTPModule::GetManufacturerLabelHandler(
×
1559
    HTTPResponse *response,
1560
    unsigned int universe_id,
1561
    const UID uid,
1562
    const ola::rdm::ResponseStatus &status,
1563
    const string &label) {
1564
  if (CheckForRDMError(response, status)) {
×
1565
    return;
×
1566
  }
1567
  JsonSection section;
×
1568
  section.AddItem(new StringItem("Manufacturer Label", label));
×
1569
  RespondWithSection(response, section);
×
1570

1571
  // update the map as well
1572
  uid_resolution_state *uid_state = GetUniverseUids(universe_id);
×
1573
  if (uid_state) {
×
1574
    map<UID, resolved_uid>::iterator uid_iter =
×
1575
      uid_state->resolved_uids.find(uid);
×
1576
    if (uid_iter != uid_state->resolved_uids.end()) {
×
1577
      uid_iter->second.manufacturer = label;
×
1578
    }
1579
  }
1580
}
×
1581

1582

1583
/**
1584
 * @brief Handle the request for the Device label.
1585
 */
1586
string RDMHTTPModule::GetDeviceLabel(OLA_UNUSED const HTTPRequest *request,
×
1587
                                     HTTPResponse *response,
1588
                                     unsigned int universe_id,
1589
                                     const UID &uid) {
1590
  string error;
×
1591
  m_rdm_api.GetDeviceLabel(
×
1592
      universe_id,
1593
      uid,
1594
      ola::rdm::ROOT_RDM_DEVICE,
1595
      NewSingleCallback(this,
×
1596
                        &RDMHTTPModule::GetDeviceLabelHandler,
1597
                        response,
1598
                        universe_id,
1599
                        uid),
1600
      &error);
1601
  return error;
×
1602
}
×
1603

1604

1605
/**
1606
 * @brief Handle the response to a device label call and build the response
1607
 */
1608
void RDMHTTPModule::GetDeviceLabelHandler(
×
1609
    HTTPResponse *response,
1610
    unsigned int universe_id,
1611
    const UID uid,
1612
    const ola::rdm::ResponseStatus &status,
1613
    const string &label) {
1614
  if (CheckForRDMError(response, status)) {
×
1615
    return;
×
1616
  }
1617

1618
  JsonSection section;
×
1619
  section.AddItem(new StringItem("Device Label", label, LABEL_FIELD));
×
1620
  RespondWithSection(response, section);
×
1621

1622
  // update the map as well
1623
  uid_resolution_state *uid_state = GetUniverseUids(universe_id);
×
1624
  if (uid_state) {
×
1625
    map<UID, resolved_uid>::iterator uid_iter =
×
1626
      uid_state->resolved_uids.find(uid);
×
1627
    if (uid_iter != uid_state->resolved_uids.end()) {
×
1628
      uid_iter->second.device = label;
×
1629
    }
1630
  }
1631
}
×
1632

1633

1634
/*
1635
 * @brief Set the device label
1636
 */
1637
string RDMHTTPModule::SetDeviceLabel(const HTTPRequest *request,
×
1638
                                     HTTPResponse *response,
1639
                                     unsigned int universe_id,
1640
                                     const UID &uid) {
1641
  string label = request->GetParameter(LABEL_FIELD);
×
1642
  string error;
×
1643
  m_rdm_api.SetDeviceLabel(
×
1644
      universe_id,
1645
      uid,
1646
      ola::rdm::ROOT_RDM_DEVICE,
1647
      label,
1648
      NewSingleCallback(this,
1649
                        &RDMHTTPModule::SetHandler,
1650
                        response),
1651
      &error);
1652
  return error;
×
1653
}
×
1654

1655

1656
/**
1657
 * @brief Handle the request for the factory defaults section
1658
 */
1659
string RDMHTTPModule::GetFactoryDefaults(HTTPResponse *response,
×
1660
                                         unsigned int universe_id,
1661
                                         const UID &uid) {
1662
  string error;
×
1663
  m_rdm_api.GetFactoryDefaults(
×
1664
      universe_id,
1665
      uid,
1666
      ola::rdm::ROOT_RDM_DEVICE,
1667
      NewSingleCallback(this,
1668
                        &RDMHTTPModule::FactoryDefaultsHandler,
1669
                        response),
1670
      &error);
1671
  return error;
×
1672
}
×
1673

1674

1675
/**
1676
 * @brief Handle the response to a factory defaults call and build the response
1677
 */
1678
void RDMHTTPModule::FactoryDefaultsHandler(
×
1679
    HTTPResponse *response,
1680
    const ola::rdm::ResponseStatus &status,
1681
    bool defaults) {
1682
  if (CheckForRDMError(response, status)) {
×
1683
    return;
×
1684
  }
1685

1686
  JsonSection section;
×
1687
  section.AddItem(new StringItem("Using Defaults",
×
1688
                                 defaults ? "Yes" : "No"));
×
1689
  section.AddItem(new HiddenItem("1", GENERIC_UINT_FIELD));
×
1690
  section.SetSaveButton("Reset to Defaults");
×
1691
  RespondWithSection(response, section);
×
1692
}
×
1693

1694

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

1713

1714
/**
1715
 * @brief Handle the request for the language section.
1716
 */
1717
string RDMHTTPModule::GetLanguage(HTTPResponse *response,
×
1718
                                  unsigned int universe_id,
1719
                                  const UID &uid) {
1720
  string error;
×
1721
  m_rdm_api.GetLanguageCapabilities(
×
1722
      universe_id,
1723
      uid,
1724
      ola::rdm::ROOT_RDM_DEVICE,
1725
      NewSingleCallback(this,
×
1726
                        &RDMHTTPModule::GetSupportedLanguagesHandler,
1727
                        response,
1728
                        universe_id,
1729
                        uid),
1730
      &error);
1731
  return error;
×
1732
}
×
1733

1734

1735
/**
1736
 * @brief Handle the response to language capability call.
1737
 */
1738
void RDMHTTPModule::GetSupportedLanguagesHandler(
×
1739
    HTTPResponse *response,
1740
    unsigned int universe_id,
1741
    const UID uid,
1742
    OLA_UNUSED const ola::rdm::ResponseStatus &status,
1743
    const vector<string> &languages) {
1744
  string error;
×
1745
  m_rdm_api.GetLanguage(
×
1746
      universe_id,
1747
      uid,
1748
      ola::rdm::ROOT_RDM_DEVICE,
1749
      NewSingleCallback(this,
×
1750
                        &RDMHTTPModule::GetLanguageHandler,
1751
                        response,
1752
                        languages),
1753
      &error);
1754

1755
  if (!error.empty()) {
×
1756
    m_server->ServeError(response, BACKEND_DISCONNECTED_ERROR + error);
×
1757
  }
1758
}
×
1759

1760

1761
/**
1762
 * @brief Handle the response to language call and build the response
1763
 */
1764
void RDMHTTPModule::GetLanguageHandler(HTTPResponse *response,
×
1765
                                       vector<string> languages,
1766
                                       const ola::rdm::ResponseStatus &status,
1767
                                       const string &language) {
1768
  JsonSection section;
×
1769
  SelectItem *item = new SelectItem("Language", LANGUAGE_FIELD);
×
1770
  bool ok = CheckForRDMSuccess(status);
×
1771

1772
  vector<string>::const_iterator iter = languages.begin();
×
1773
  unsigned int i = 0;
×
1774
  for (; iter != languages.end(); ++iter, i++) {
×
1775
    item->AddItem(*iter, *iter);
×
1776
    if (ok && *iter == language) {
×
1777
      item->SetSelectedOffset(i);
×
1778
    }
1779
  }
1780

1781
  if (ok && languages.empty()) {
×
1782
    item->AddItem(language, language);
×
1783
    item->SetSelectedOffset(0);
×
1784
  }
1785
  section.AddItem(item);
×
1786
  RespondWithSection(response, section);
×
1787
}
×
1788

1789

1790
/*
1791
 * @brief Set the language
1792
 */
1793
string RDMHTTPModule::SetLanguage(const HTTPRequest *request,
×
1794
                                  HTTPResponse *response,
1795
                                  unsigned int universe_id,
1796
                                  const UID &uid) {
1797
  string label = request->GetParameter(LANGUAGE_FIELD);
×
1798
  string error;
×
1799
  m_rdm_api.SetLanguage(
×
1800
      universe_id,
1801
      uid,
1802
      ola::rdm::ROOT_RDM_DEVICE,
1803
      label,
1804
      NewSingleCallback(this,
1805
                        &RDMHTTPModule::SetHandler,
1806
                        response),
1807
      &error);
1808
  return error;
×
1809
}
×
1810

1811

1812
/**
1813
 * @brief Handle the request for the boot software section.
1814
 */
1815
string RDMHTTPModule::GetBootSoftware(HTTPResponse *response,
×
1816
                                      unsigned int universe_id,
1817
                                      const UID &uid) {
1818
  string error;
×
1819
  m_rdm_api.GetBootSoftwareVersionLabel(
×
1820
      universe_id,
1821
      uid,
1822
      ola::rdm::ROOT_RDM_DEVICE,
1823
      NewSingleCallback(this,
×
1824
                        &RDMHTTPModule::GetBootSoftwareLabelHandler,
1825
                        response,
1826
                        universe_id,
1827
                        uid),
1828
      &error);
1829
  return error;
×
1830
}
×
1831

1832

1833
/**
1834
 * @brief Handle the response to a boot software label.
1835
 */
1836
void RDMHTTPModule::GetBootSoftwareLabelHandler(
×
1837
    HTTPResponse *response,
1838
    unsigned int universe_id,
1839
    const UID uid,
1840
    OLA_UNUSED const ola::rdm::ResponseStatus &status,
1841
    const string &label) {
1842
  string error;
×
1843
  m_rdm_api.GetBootSoftwareVersion(
×
1844
      universe_id,
1845
      uid,
1846
      ola::rdm::ROOT_RDM_DEVICE,
1847
      NewSingleCallback(this,
×
1848
                        &RDMHTTPModule::GetBootSoftwareVersionHandler,
1849
                        response,
1850
                        label),
1851
      &error);
1852
  if (!error.empty()) {
×
1853
    m_server->ServeError(response, BACKEND_DISCONNECTED_ERROR + error);
×
1854
  }
1855
}
×
1856

1857

1858
/**
1859
 * @brief Handle the response to a boot software version.
1860
 */
1861
void RDMHTTPModule::GetBootSoftwareVersionHandler(
×
1862
    HTTPResponse *response,
1863
    string label,
1864
    const ola::rdm::ResponseStatus &status,
1865
    uint32_t version) {
1866
  ostringstream str;
×
1867
  str << label;
×
1868
  if (CheckForRDMSuccess(status)) {
×
1869
    if (!label.empty()) {
×
1870
      str << " (" << version << ")";
×
1871
    } else {
1872
      str << version;
×
1873
    }
1874
  }
1875

1876
  JsonSection section;
×
1877
  StringItem *item = new StringItem("Boot Software", str.str());
×
1878
  section.AddItem(item);
×
1879
  RespondWithSection(response, section);
×
1880
}
×
1881

1882

1883
/**
1884
 * @brief Handle the request for the personality section.
1885
 */
1886
string RDMHTTPModule::GetPersonalities(OLA_UNUSED const HTTPRequest *request,
×
1887
                                       HTTPResponse *response,
1888
                                       unsigned int universe_id,
1889
                                       const UID &uid,
1890
                                       bool return_as_section,
1891
                                       bool include_descriptions) {
1892
  string hint = request->GetParameter(HINT_KEY);
×
1893
  string error;
×
1894

1895
  personality_info *info = new personality_info;
×
1896
  info->universe_id = universe_id;
×
1897
  info->uid = new UID(uid);
×
1898
  info->include_descriptions = include_descriptions || (hint == "l");
×
1899
  info->return_as_section = return_as_section;
×
1900
  info->active = 0;
×
1901
  info->next = 1;
×
1902
  info->total = 0;
×
1903

1904
  m_rdm_api.GetDMXPersonality(
×
1905
      universe_id,
1906
      uid,
1907
      ola::rdm::ROOT_RDM_DEVICE,
1908
      NewSingleCallback(this,
1909
                        &RDMHTTPModule::GetPersonalityHandler,
1910
                        response,
1911
                        info),
1912
      &error);
1913
  return error;
×
1914
}
×
1915

1916

1917
/**
1918
 * @brief Handle the response to a dmx personality call.
1919
 */
1920
void RDMHTTPModule::GetPersonalityHandler(
×
1921
    HTTPResponse *response,
1922
    personality_info *info,
1923
    const ola::rdm::ResponseStatus &status,
1924
    uint8_t current,
1925
    uint8_t total) {
1926
  if (CheckForRDMError(response, status)) {
×
1927
    delete info->uid;
×
1928
    delete info;
×
1929
    return;
×
1930
  }
1931

1932
  info->active = current;
×
1933
  info->total = total;
×
1934

1935
  if (info->include_descriptions) {
×
1936
    GetNextPersonalityDescription(response, info);
×
1937
  } else {
1938
    SendPersonalityResponse(response, info);
×
1939
  }
1940
}
1941

1942

1943
/**
1944
 * @brief Get the description of the next dmx personality
1945
 */
1946
void RDMHTTPModule::GetNextPersonalityDescription(HTTPResponse *response,
×
1947
                                                  personality_info *info) {
1948
  string error;
×
1949
  while (info->next <= info->total) {
×
1950
    bool r = m_rdm_api.GetDMXPersonalityDescription(
×
1951
        info->universe_id,
1952
        *(info->uid),
×
1953
        ola::rdm::ROOT_RDM_DEVICE,
1954
        info->next,
×
1955
        NewSingleCallback(this,
1956
                          &RDMHTTPModule::GetPersonalityLabelHandler,
1957
                          response,
1958
                          info),
1959
        &error);
1960
    if (r) {
×
1961
      return;
×
1962
    }
1963

1964
    info->next++;
×
1965
  }
1966
  if (info->return_as_section) {
×
1967
    SendSectionPersonalityResponse(response, info);
×
1968
  } else {
1969
    SendPersonalityResponse(response, info);
×
1970
  }
1971
}
×
1972

1973

1974
/**
1975
 * @brief Handle the response to a Personality label call.
1976
 *
1977
 * This fetches the next personality in the sequence, or sends the response if
1978
 * we have all the info.
1979
 */
1980
void RDMHTTPModule::GetPersonalityLabelHandler(
×
1981
    HTTPResponse *response,
1982
    personality_info *info,
1983
    const ola::rdm::ResponseStatus &status,
1984
    OLA_UNUSED uint8_t personality,
1985
    uint16_t slot_count,
1986
    const string &label) {
1987
  string description = "";
×
1988
  uint32_t slots = INVALID_PERSONALITY;
×
1989

1990
  if (CheckForRDMSuccess(status)) {
×
1991
    slots = slot_count;
×
1992
    description = label;
×
1993
  }
1994

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

1997
  if (info->next == info->total) {
×
1998
    if (info->return_as_section) {
×
1999
      SendSectionPersonalityResponse(response, info);
×
2000
    } else {
2001
      SendPersonalityResponse(response, info);
×
2002
    }
2003
  } else {
2004
    info->next++;
×
2005
    GetNextPersonalityDescription(response, info);
×
2006
  }
2007
}
×
2008

2009

2010
/**
2011
 * @brief Send the response to a dmx personality section
2012
 */
2013
void RDMHTTPModule::SendSectionPersonalityResponse(HTTPResponse *response,
×
2014
                                                   personality_info *info) {
2015
  JsonSection section;
×
2016
  SelectItem *item = new SelectItem("Personality", GENERIC_UINT_FIELD);
×
2017

2018
  for (unsigned int i = 1; i <= info->total; i++) {
×
2019
    if (i <= info->personalities.size() &&
×
2020
        info->personalities[i - 1].first != INVALID_PERSONALITY) {
×
2021
      ostringstream str;
×
2022
      str << info->personalities[i - 1].second << " (" <<
×
2023
        info->personalities[i - 1].first << ")";
×
2024
      item->AddItem(str.str(), i);
×
2025
    } else {
×
2026
      item->AddItem(IntToString(i), i);
×
2027
    }
2028

2029
    if (info->active == i) {
×
2030
      item->SetSelectedOffset(i - 1);
×
2031
    }
2032
  }
2033
  section.AddItem(item);
×
2034
  RespondWithSection(response, section);
×
2035

2036
  delete info->uid;
×
2037
  delete info;
×
2038
}
×
2039

2040

2041
/**
2042
 * @brief Set the personality
2043
 */
2044
string RDMHTTPModule::SetPersonality(const HTTPRequest *request,
×
2045
                                     HTTPResponse *response,
2046
                                     unsigned int universe_id,
2047
                                     const UID &uid) {
2048
  string personality_str = request->GetParameter(GENERIC_UINT_FIELD);
×
2049
  uint8_t personality;
×
2050

2051
  if (!StringToInt(personality_str, &personality)) {
×
2052
    return "Invalid personality";
×
2053
  }
2054

2055
  string error;
×
2056
  m_rdm_api.SetDMXPersonality(
×
2057
      universe_id,
2058
      uid,
2059
      ola::rdm::ROOT_RDM_DEVICE,
2060
      personality,
2061
      NewSingleCallback(this,
2062
                        &RDMHTTPModule::SetHandler,
2063
                        response),
2064
      &error);
2065
  return error;
×
2066
}
×
2067

2068

2069
/**
2070
 * @brief Handle the request for the start address section.
2071
 */
2072
string RDMHTTPModule::GetStartAddress(OLA_UNUSED const HTTPRequest *request,
×
2073
                                      HTTPResponse *response,
2074
                                      unsigned int universe_id,
2075
                                      const UID &uid) {
2076
  string error;
×
2077
  m_rdm_api.GetDMXAddress(
×
2078
      universe_id,
2079
      uid,
2080
      ola::rdm::ROOT_RDM_DEVICE,
2081
      NewSingleCallback(this,
2082
                        &RDMHTTPModule::GetStartAddressHandler,
2083
                        response),
2084
      &error);
2085
  return error;
×
2086
}
×
2087

2088

2089
/**
2090
 * @brief Handle the response to a dmx start address call and build the response
2091
 */
2092
void RDMHTTPModule::GetStartAddressHandler(
×
2093
    HTTPResponse *response,
2094
    const ola::rdm::ResponseStatus &status,
2095
    uint16_t address) {
2096
  if (CheckForRDMError(response, status)) {
×
2097
    return;
×
2098
  }
2099

2100
  JsonSection section;
×
2101
  GenericItem *item = NULL;
×
2102
  if (address == ola::rdm::ZERO_FOOTPRINT_DMX_ADDRESS) {
×
2103
    item = new StringItem("DMX Start Address", "N/A");
×
2104
  } else {
2105
    UIntItem *uint_item = new UIntItem("DMX Start Address", address,
×
2106
                                       ADDRESS_FIELD);
×
2107
    uint_item->SetMin(DMX_MIN_SLOT_NUMBER);
×
2108
    uint_item->SetMax(DMX_MAX_SLOT_NUMBER);
×
2109
    item = uint_item;
×
2110
  }
2111
  section.AddItem(item);
×
2112
  RespondWithSection(response, section);
×
2113
}
×
2114

2115

2116
/*
2117
 * @brief Set the DMX start address
2118
 */
2119
string RDMHTTPModule::SetStartAddress(const HTTPRequest *request,
×
2120
                                      HTTPResponse *response,
2121
                                      unsigned int universe_id,
2122
                                      const UID &uid) {
2123
  string dmx_address = request->GetParameter(ADDRESS_FIELD);
×
2124
  uint16_t address;
×
2125

2126
  if (!StringToInt(dmx_address, &address)) {
×
2127
    return "Invalid start address";
×
2128
  }
2129

2130
  string error;
×
2131
  m_rdm_api.SetDMXAddress(
×
2132
      universe_id,
2133
      uid,
2134
      ola::rdm::ROOT_RDM_DEVICE,
2135
      address,
2136
      NewSingleCallback(this,
2137
                        &RDMHTTPModule::SetHandler,
2138
                        response),
2139
      &error);
2140
  return error;
×
2141
}
×
2142

2143

2144
/**
2145
 * @brief Handle the request for the sensor section.
2146
 */
2147
string RDMHTTPModule::GetSensor(const HTTPRequest *request,
×
2148
                                HTTPResponse *response,
2149
                                unsigned int universe_id,
2150
                                const UID &uid) {
2151
  string hint = request->GetParameter(HINT_KEY);
×
2152
  uint8_t sensor_id;
×
2153
  if (!StringToInt(hint, &sensor_id)) {
×
2154
    return "Invalid hint (sensor #)";
×
2155
  }
2156

2157
  string error;
×
2158
  m_rdm_api.GetSensorDefinition(
×
2159
      universe_id,
2160
      uid,
2161
      ola::rdm::ROOT_RDM_DEVICE,
2162
      sensor_id,
2163
      NewSingleCallback(this,
×
2164
                        &RDMHTTPModule::SensorDefinitionHandler,
2165
                        response,
2166
                        universe_id,
2167
                        uid,
2168
                        sensor_id),
2169
      &error);
2170
  return error;
×
2171
}
×
2172

2173

2174
/**
2175
 * @brief Handle the response to a sensor definition request.
2176
 */
2177
void RDMHTTPModule::SensorDefinitionHandler(
×
2178
    HTTPResponse *response,
2179
    unsigned int universe_id,
2180
    const UID uid,
2181
    uint8_t sensor_id,
2182
    const ola::rdm::ResponseStatus &status,
2183
    const ola::rdm::SensorDescriptor &definition) {
2184
  ola::rdm::SensorDescriptor *definition_arg = NULL;
×
2185

2186
  if (CheckForRDMSuccess(status)) {
×
2187
    definition_arg = new ola::rdm::SensorDescriptor();
×
2188
    *definition_arg = definition;
×
2189
  }
2190
  string error;
×
2191
  m_rdm_api.GetSensorValue(
×
2192
      universe_id,
2193
      uid,
2194
      ola::rdm::ROOT_RDM_DEVICE,
2195
      sensor_id,
2196
      NewSingleCallback(this,
2197
                        &RDMHTTPModule::SensorValueHandler,
2198
                        response,
2199
                        definition_arg),
2200
      &error);
2201
  if (!error.empty()) {
×
2202
    m_server->ServeError(response, BACKEND_DISCONNECTED_ERROR + error);
×
2203
  }
2204
}
×
2205

2206

2207
/**
2208
 * @brief Handle the response to a sensor value request & build the response.
2209
 */
2210
void RDMHTTPModule::SensorValueHandler(
×
2211
    HTTPResponse *response,
2212
    ola::rdm::SensorDescriptor *definition,
2213
    const ola::rdm::ResponseStatus &status,
2214
    const ola::rdm::SensorValueDescriptor &value) {
2215
  if (CheckForRDMError(response, status)) {
×
2216
    if (definition) {
×
2217
      delete definition;
×
2218
    }
2219
    return;
×
2220
  }
2221

2222
  JsonSection section;
×
2223
  ostringstream str;
×
2224

2225
  if (definition) {
×
2226
    section.AddItem(new StringItem("Description", definition->description));
×
2227
  }
2228

2229
  str << value.present_value;
×
2230
  if (definition) {
×
2231
    str << " " << ola::rdm::PrefixToString(definition->prefix) << " "
×
2232
        << ola::rdm::UnitToString(definition->unit);
×
2233
  }
2234
  section.AddItem(new StringItem("Present Value", str.str()));
×
2235

2236
  if (definition) {
×
2237
    section.AddItem(new StringItem(
×
2238
          "Type",
2239
          ola::rdm::SensorTypeToString(definition->type)));
×
2240
    str.str("");
×
2241
    str << definition->range_min << " - " << definition->range_max << " "
×
2242
        << ola::rdm::PrefixToString(definition->prefix) << " " <<
×
2243
      ola::rdm::UnitToString(definition->unit);
×
2244
    section.AddItem(new StringItem("Range", str.str()));
×
2245

2246
    str.str("");
×
2247
    str << definition->normal_min << " - " << definition->normal_max << " "
×
2248
        << ola::rdm::PrefixToString(definition->prefix) << " " <<
×
2249
      ola::rdm::UnitToString(definition->unit);
×
2250
    section.AddItem(new StringItem("Normal Range", str.str()));
×
2251

2252
    if (definition->recorded_value_support &
×
2253
        ola::rdm::SENSOR_RECORDED_VALUE) {
2254
      str.str("");
×
2255
      str << value.recorded << " "
×
2256
          << ola::rdm::PrefixToString(definition->prefix) << " "
×
2257
          << ola::rdm::UnitToString(definition->unit);
×
2258
      section.AddItem(new StringItem("Recorded Value", str.str()));
×
2259
    }
2260

2261
    if (definition->recorded_value_support &
×
2262
        ola::rdm::SENSOR_RECORDED_RANGE_VALUES) {
2263
      str.str("");
×
2264
      str << value.lowest << " - " << value.highest << " "
×
2265
          << ola::rdm::PrefixToString(definition->prefix) << " "
×
2266
          << ola::rdm::UnitToString(definition->unit);
×
2267
      section.AddItem(new StringItem("Min / Max Recorded Values", str.str()));
×
2268
    }
2269
  }
2270

2271
  if (definition && definition->recorded_value_support) {
×
2272
    section.AddItem(new HiddenItem("1", RECORD_SENSOR_FIELD));
×
2273
  }
2274
  section.SetSaveButton("Record Sensor");
×
2275
  RespondWithSection(response, section);
×
2276
  delete definition;
×
2277
}
×
2278

2279

2280
/*
2281
 * @brief Record a sensor value
2282
 */
2283
string RDMHTTPModule::RecordSensor(const HTTPRequest *request,
×
2284
                                   HTTPResponse *response,
2285
                                   unsigned int universe_id,
2286
                                   const UID &uid) {
2287
  string hint = request->GetParameter(HINT_KEY);
×
2288
  uint8_t sensor_id;
×
2289
  if (!StringToInt(hint, &sensor_id)) {
×
2290
    return "Invalid hint (sensor #)";
×
2291
  }
2292

2293
  string error;
×
2294
  m_rdm_api.RecordSensors(
×
2295
      universe_id,
2296
      uid,
2297
      ola::rdm::ROOT_RDM_DEVICE,
2298
      sensor_id,
2299
      NewSingleCallback(this,
2300
                        &RDMHTTPModule::SetHandler,
2301
                        response),
2302
      &error);
2303
  return error;
×
2304
}
×
2305

2306

2307
/**
2308
 * @brief Handle the request for the device hours section.
2309
 */
2310
string RDMHTTPModule::GetDeviceHours(OLA_UNUSED const HTTPRequest *request,
×
2311
                                     HTTPResponse *response,
2312
                                     unsigned int universe_id,
2313
                                     const UID &uid) {
2314
  string error;
×
2315
  m_rdm_api.GetDeviceHours(
×
2316
      universe_id,
2317
      uid,
2318
      ola::rdm::ROOT_RDM_DEVICE,
2319
      NewSingleCallback(this,
2320
                        &RDMHTTPModule::GenericUIntHandler,
2321
                        response,
2322
                        string("Device Hours")),
×
2323
      &error);
2324
  return error;
×
2325
}
×
2326

2327

2328
/**
2329
 * @brief Set the device hours
2330
 */
2331
string RDMHTTPModule::SetDeviceHours(const HTTPRequest *request,
×
2332
                                     HTTPResponse *response,
2333
                                     unsigned int universe_id,
2334
                                     const UID &uid) {
2335
  string device_hours = request->GetParameter(GENERIC_UINT_FIELD);
×
2336
  uint32_t dev_hours;
×
2337

2338
  if (!StringToInt(device_hours, &dev_hours)) {
×
2339
    return "Invalid device hours";
×
2340
  }
2341

2342
  string error;
×
2343
  m_rdm_api.SetDeviceHours(
×
2344
      universe_id,
2345
      uid,
2346
      ola::rdm::ROOT_RDM_DEVICE,
2347
      dev_hours,
2348
      NewSingleCallback(this,
2349
                        &RDMHTTPModule::SetHandler,
2350
                        response),
2351
      &error);
2352
  return error;
×
2353
}
×
2354

2355

2356
/**
2357
 * @brief Handle the request for the lamp hours section.
2358
 */
2359
string RDMHTTPModule::GetLampHours(OLA_UNUSED const HTTPRequest *request,
×
2360
                                   HTTPResponse *response,
2361
                                   unsigned int universe_id,
2362
                                   const UID &uid) {
2363
  string error;
×
2364
  m_rdm_api.GetLampHours(
×
2365
      universe_id,
2366
      uid,
2367
      ola::rdm::ROOT_RDM_DEVICE,
2368
      NewSingleCallback(this,
2369
                        &RDMHTTPModule::GenericUIntHandler,
2370
                        response,
2371
                        string("Lamp Hours")),
×
2372
      &error);
2373
  return error;
×
2374
}
×
2375

2376

2377
/**
2378
 * @brief Set the lamp hours
2379
 */
2380
string RDMHTTPModule::SetLampHours(const HTTPRequest *request,
×
2381
                                   HTTPResponse *response,
2382
                                   unsigned int universe_id,
2383
                                   const UID &uid) {
2384
  string lamp_hours_str = request->GetParameter(GENERIC_UINT_FIELD);
×
2385
  uint32_t lamp_hours;
×
2386

2387
  if (!StringToInt(lamp_hours_str, &lamp_hours)) {
×
2388
    return "Invalid lamp hours";
×
2389
  }
2390

2391
  string error;
×
2392
  m_rdm_api.SetLampHours(
×
2393
      universe_id,
2394
      uid,
2395
      ola::rdm::ROOT_RDM_DEVICE,
2396
      lamp_hours,
2397
      NewSingleCallback(this,
2398
                        &RDMHTTPModule::SetHandler,
2399
                        response),
2400
      &error);
2401
  return error;
×
2402
}
×
2403

2404

2405
/**
2406
 * @brief Handle the request for the lamp strikes section
2407
 */
2408
string RDMHTTPModule::GetLampStrikes(OLA_UNUSED const HTTPRequest *request,
×
2409
                                     HTTPResponse *response,
2410
                                     unsigned int universe_id,
2411
                                     const UID &uid) {
2412
  string error;
×
2413
  m_rdm_api.GetLampStrikes(
×
2414
      universe_id,
2415
      uid,
2416
      ola::rdm::ROOT_RDM_DEVICE,
2417
      NewSingleCallback(this,
2418
                        &RDMHTTPModule::GenericUIntHandler,
2419
                        response,
2420
                        string("Lamp Strikes")),
×
2421
      &error);
2422
  return error;
×
2423
}
×
2424

2425

2426
/**
2427
 * @brief Set the lamp strikes
2428
 */
2429
string RDMHTTPModule::SetLampStrikes(const HTTPRequest *request,
×
2430
                                     HTTPResponse *response,
2431
                                     unsigned int universe_id,
2432
                                     const UID &uid) {
2433
  string lamp_strikes_str = request->GetParameter(GENERIC_UINT_FIELD);
×
2434
  uint32_t lamp_strikes;
×
2435

2436
  if (!StringToInt(lamp_strikes_str, &lamp_strikes)) {
×
2437
    return "Invalid lamp strikes";
×
2438
  }
2439

2440
  string error;
×
2441
  m_rdm_api.SetLampStrikes(
×
2442
      universe_id,
2443
      uid,
2444
      ola::rdm::ROOT_RDM_DEVICE,
2445
      lamp_strikes,
2446
      NewSingleCallback(this,
2447
                        &RDMHTTPModule::SetHandler,
2448
                        response),
2449
      &error);
2450
  return error;
×
2451
}
×
2452

2453

2454
/**
2455
 * @brief Handle the request for the lamp state section
2456
 */
2457
string RDMHTTPModule::GetLampState(OLA_UNUSED const HTTPRequest *request,
×
2458
                                   HTTPResponse *response,
2459
                                   unsigned int universe_id,
2460
                                   const UID &uid) {
2461
  string error;
×
2462
  m_rdm_api.GetLampState(
×
2463
      universe_id,
2464
      uid,
2465
      ola::rdm::ROOT_RDM_DEVICE,
2466
      NewSingleCallback(this,
2467
                        &RDMHTTPModule::LampStateHandler,
2468
                        response),
2469
      &error);
2470
  return error;
×
2471
}
×
2472

2473

2474
/**
2475
 * @brief Handle the response to lamp state call and build the response
2476
 */
2477
void RDMHTTPModule::LampStateHandler(HTTPResponse *response,
×
2478
                                     const ola::rdm::ResponseStatus &status,
2479
                                     uint8_t state) {
2480
  if (CheckForRDMError(response, status)) {
×
2481
    return;
×
2482
  }
2483

2484
  JsonSection section;
×
2485
  SelectItem *item = new SelectItem("Lamp State", GENERIC_UINT_FIELD);
×
2486

2487
  typedef struct {
×
2488
    string label;
2489
    ola::rdm::rdm_lamp_state state;
2490
  } values_s;
×
2491

2492
  values_s possible_values[] = {
×
2493
    {"Off", ola::rdm::LAMP_OFF},
×
2494
    {"On", ola::rdm::LAMP_ON},
2495
    {"Strike", ola::rdm::LAMP_STRIKE},
2496
    {"Standby", ola::rdm::LAMP_STANDBY}};
×
2497

2498
  for (unsigned int i = 0; i < sizeof(possible_values) / sizeof(values_s);
×
2499
       ++i) {
2500
    item->AddItem(possible_values[i].label, possible_values[i].state);
×
2501
    if (state == possible_values[i].state) {
×
2502
      item->SetSelectedOffset(i);
×
2503
    }
2504
  }
2505

2506
  section.AddItem(item);
×
2507
  RespondWithSection(response, section);
×
2508
}
×
2509

2510

2511
/**
2512
 * @brief Set the lamp state
2513
 */
2514
string RDMHTTPModule::SetLampState(const HTTPRequest *request,
×
2515
                                   HTTPResponse *response,
2516
                                   unsigned int universe_id,
2517
                                   const UID &uid) {
2518
  string lamp_state_str = request->GetParameter(GENERIC_UINT_FIELD);
×
2519
  uint8_t lamp_state;
×
2520
  if (!StringToInt(lamp_state_str, &lamp_state)) {
×
2521
    return "Invalid lamp state";
×
2522
  }
2523

2524
  string error;
×
2525
  m_rdm_api.SetLampState(
×
2526
      universe_id,
2527
      uid,
2528
      ola::rdm::ROOT_RDM_DEVICE,
2529
      lamp_state,
2530
      NewSingleCallback(this,
2531
                        &RDMHTTPModule::SetHandler,
2532
                        response),
2533
      &error);
2534
  return error;
×
2535
}
×
2536

2537

2538
/**
2539
 * @brief Handle the request for the lamp mode section
2540
 */
2541
string RDMHTTPModule::GetLampMode(OLA_UNUSED const HTTPRequest *request,
×
2542
                                  HTTPResponse *response,
2543
                                  unsigned int universe_id,
2544
                                  const UID &uid) {
2545
  string error;
×
2546
  m_rdm_api.GetLampMode(
×
2547
      universe_id,
2548
      uid,
2549
      ola::rdm::ROOT_RDM_DEVICE,
2550
      NewSingleCallback(this,
2551
                        &RDMHTTPModule::LampModeHandler,
2552
                        response),
2553
      &error);
2554
  return error;
×
2555
}
×
2556

2557

2558
/**
2559
 * @brief Handle the response to lamp mode call and build the response
2560
 */
2561
void RDMHTTPModule::LampModeHandler(HTTPResponse *response,
×
2562
                                    const ola::rdm::ResponseStatus &status,
2563
                                    uint8_t mode) {
2564
  if (CheckForRDMError(response, status)) {
×
2565
    return;
×
2566
  }
2567

2568
  JsonSection section;
×
2569
  SelectItem *item = new SelectItem("Lamp Mode", GENERIC_UINT_FIELD);
×
2570

2571
  typedef struct {
×
2572
    string label;
2573
    ola::rdm::rdm_lamp_mode mode;
2574
  } values_s;
×
2575

2576
  values_s possible_values[] = {
×
2577
    {"Off", ola::rdm::LAMP_ON_MODE_OFF},
×
2578
    {"DMX", ola::rdm::LAMP_ON_MODE_DMX},
2579
    {"On", ola::rdm::LAMP_ON_MODE_ON},
2580
    {"On After Calibration", ola::rdm::LAMP_ON_MODE_ON_AFTER_CAL}};
×
2581

2582
  for (unsigned int i = 0; i < sizeof(possible_values) / sizeof(values_s);
×
2583
       ++i) {
2584
    item->AddItem(possible_values[i].label, possible_values[i].mode);
×
2585
    if (mode == possible_values[i].mode) {
×
2586
      item->SetSelectedOffset(i);
×
2587
    }
2588
  }
2589

2590
  section.AddItem(item);
×
2591
  RespondWithSection(response, section);
×
2592
}
×
2593

2594

2595
/**
2596
 * @brief Set the lamp mode
2597
 */
2598
string RDMHTTPModule::SetLampMode(const HTTPRequest *request,
×
2599
                                  HTTPResponse *response,
2600
                                  unsigned int universe_id,
2601
                                  const UID &uid) {
2602
  string lamp_mode_str = request->GetParameter(GENERIC_UINT_FIELD);
×
2603
  uint8_t lamp_mode;
×
2604
  if (!StringToInt(lamp_mode_str, &lamp_mode)) {
×
2605
    return "Invalid lamp mode";
×
2606
  }
2607

2608
  string error;
×
2609
  m_rdm_api.SetLampMode(
×
2610
      universe_id,
2611
      uid,
2612
      ola::rdm::ROOT_RDM_DEVICE,
2613
      lamp_mode,
2614
      NewSingleCallback(this,
2615
                        &RDMHTTPModule::SetHandler,
2616
                        response),
2617
      &error);
2618
  return error;
×
2619
}
×
2620

2621

2622
/**
2623
 * @brief Handle the request for the device power cycles section
2624
 */
2625
string RDMHTTPModule::GetPowerCycles(OLA_UNUSED const HTTPRequest *request,
×
2626
                                     HTTPResponse *response,
2627
                                     unsigned int universe_id,
2628
                                     const UID &uid) {
2629
  string error;
×
2630
  m_rdm_api.GetDevicePowerCycles(
×
2631
      universe_id,
2632
      uid,
2633
      ola::rdm::ROOT_RDM_DEVICE,
2634
      NewSingleCallback(this,
2635
                        &RDMHTTPModule::GenericUIntHandler,
2636
                        response,
2637
                        string("Device Power Cycles")),
×
2638
      &error);
2639
  return error;
×
2640
}
×
2641

2642

2643
/**
2644
 * @brief Set the device power cycles
2645
 */
2646
string RDMHTTPModule::SetPowerCycles(const HTTPRequest *request,
×
2647
                                     HTTPResponse *response,
2648
                                     unsigned int universe_id,
2649
                                     const UID &uid) {
2650
  string power_cycles_str = request->GetParameter(GENERIC_UINT_FIELD);
×
2651
  uint32_t power_cycles;
×
2652

2653
  if (!StringToInt(power_cycles_str, &power_cycles)) {
×
2654
    return "Invalid power cycles";
×
2655
  }
2656

2657
  string error;
×
2658
  m_rdm_api.SetDevicePowerCycles(
×
2659
      universe_id,
2660
      uid,
2661
      ola::rdm::ROOT_RDM_DEVICE,
2662
      power_cycles,
2663
      NewSingleCallback(this,
2664
                        &RDMHTTPModule::SetHandler,
2665
                        response),
2666
      &error);
2667
  return error;
×
2668
}
×
2669

2670

2671

2672
/**
2673
 * @brief Handle the request for the display invert section.
2674
 */
2675
string RDMHTTPModule::GetDisplayInvert(HTTPResponse *response,
×
2676
                                       unsigned int universe_id,
2677
                                       const UID &uid) {
2678
  string error;
×
2679
  m_rdm_api.GetDisplayInvert(
×
2680
      universe_id,
2681
      uid,
2682
      ola::rdm::ROOT_RDM_DEVICE,
2683
      NewSingleCallback(this,
2684
                        &RDMHTTPModule::DisplayInvertHandler,
2685
                        response),
2686
      &error);
2687
  return error;
×
2688
}
×
2689

2690

2691
/**
2692
 * @brief Handle the response to display invert call and build the response
2693
 */
2694
void RDMHTTPModule::DisplayInvertHandler(
×
2695
    HTTPResponse *response,
2696
    const ola::rdm::ResponseStatus &status,
2697
    uint8_t value) {
2698
  if (CheckForRDMError(response, status)) {
×
2699
    return;
×
2700
  }
2701

2702
  JsonSection section;
×
2703
  SelectItem *item = new SelectItem("Display Invert", DISPLAY_INVERT_FIELD);
×
2704

2705
  item->AddItem("Off", ola::rdm::DISPLAY_INVERT_OFF);
×
2706
  item->AddItem("On", ola::rdm::DISPLAY_INVERT_ON);
×
2707
  item->AddItem("Auto", ola::rdm::DISPLAY_INVERT_AUTO);
×
2708

2709
  if (value < ola::rdm::DISPLAY_INVERT_MAX) {
×
2710
    item->SetSelectedOffset(value);
×
2711
  }
2712

2713
  section.AddItem(item);
×
2714
  RespondWithSection(response, section);
×
2715
}
×
2716

2717

2718
/**
2719
 * @brief Set the display invert.
2720
 */
2721
string RDMHTTPModule::SetDisplayInvert(const HTTPRequest *request,
×
2722
                                       HTTPResponse *response,
2723
                                       unsigned int universe_id,
2724
                                       const UID &uid) {
2725
  string invert_field = request->GetParameter(DISPLAY_INVERT_FIELD);
×
2726
  uint8_t display_invert;
×
2727
  if (!StringToInt(invert_field, &display_invert)) {
×
2728
    return "Invalid display invert";
×
2729
  }
2730

2731
  string error;
×
2732
  m_rdm_api.SetDisplayInvert(
×
2733
      universe_id,
2734
      uid,
2735
      ola::rdm::ROOT_RDM_DEVICE,
2736
      display_invert,
2737
      NewSingleCallback(this,
2738
                        &RDMHTTPModule::SetHandler,
2739
                        response),
2740
      &error);
2741
  return error;
×
2742
}
×
2743

2744

2745
/**
2746
 * @brief Handle the request for the display level section.
2747
 */
2748
string RDMHTTPModule::GetDisplayLevel(HTTPResponse *response,
×
2749
                                      unsigned int universe_id,
2750
                                      const UID &uid) {
2751
  string error;
×
2752
  m_rdm_api.GetDisplayLevel(
×
2753
      universe_id,
2754
      uid,
2755
      ola::rdm::ROOT_RDM_DEVICE,
2756
      NewSingleCallback(this,
2757
                        &RDMHTTPModule::DisplayLevelHandler,
2758
                        response),
2759
      &error);
2760
  return error;
×
2761
}
×
2762

2763

2764
/**
2765
 * @brief Handle the response to display level call and build the response
2766
 */
2767
void RDMHTTPModule::DisplayLevelHandler(HTTPResponse *response,
×
2768
                                        const ola::rdm::ResponseStatus &status,
2769
                                        uint8_t value) {
2770
  if (CheckForRDMError(response, status)) {
×
2771
    return;
×
2772
  }
2773

2774
  JsonSection section;
×
2775
  UIntItem *item = new UIntItem("Display Level", value, GENERIC_UINT_FIELD);
×
2776
  item->SetMin(std::numeric_limits<uint8_t>::min());
×
2777
  item->SetMax(std::numeric_limits<uint8_t>::max());
×
2778

2779
  section.AddItem(item);
×
2780
  RespondWithSection(response, section);
×
2781
}
×
2782

2783

2784
/**
2785
 * @brief Set the display level.
2786
 */
2787
string RDMHTTPModule::SetDisplayLevel(const HTTPRequest *request,
×
2788
                                      HTTPResponse *response,
2789
                                      unsigned int universe_id,
2790
                                      const UID &uid) {
2791
  string display_level_str = request->GetParameter(GENERIC_UINT_FIELD);
×
2792
  uint8_t display_level;
×
2793
  if (!StringToInt(display_level_str, &display_level)) {
×
2794
    return "Invalid display level";
×
2795
  }
2796

2797
  string error;
×
2798
  m_rdm_api.SetDisplayLevel(
×
2799
      universe_id,
2800
      uid,
2801
      ola::rdm::ROOT_RDM_DEVICE,
2802
      display_level,
2803
      NewSingleCallback(this,
2804
                        &RDMHTTPModule::SetHandler,
2805
                        response),
2806
      &error);
2807
  return error;
×
2808
}
×
2809

2810

2811
/**
2812
 * @brief Handle the request for the pan invert section.
2813
 */
2814
string RDMHTTPModule::GetPanInvert(HTTPResponse *response,
×
2815
                                   unsigned int universe_id,
2816
                                   const UID &uid) {
2817
  string error;
×
2818
  m_rdm_api.GetPanInvert(
×
2819
      universe_id,
2820
      uid,
2821
      ola::rdm::ROOT_RDM_DEVICE,
2822
      NewSingleCallback(this,
2823
                        &RDMHTTPModule::GenericUInt8BoolHandler,
2824
                        response,
2825
                        string("Pan Invert")),
×
2826
      &error);
2827
  return error;
×
2828
}
×
2829

2830

2831
/**
2832
 * @brief Set the pan invert.
2833
 */
2834
string RDMHTTPModule::SetPanInvert(const HTTPRequest *request,
×
2835
                                   HTTPResponse *response,
2836
                                   unsigned int universe_id,
2837
                                   const UID &uid) {
2838
  string mode = request->GetParameter(GENERIC_BOOL_FIELD);
×
2839
  string error;
×
2840
  m_rdm_api.SetPanInvert(
×
2841
      universe_id,
2842
      uid,
2843
      ola::rdm::ROOT_RDM_DEVICE,
2844
      mode == "1",
×
2845
      NewSingleCallback(this,
2846
                        &RDMHTTPModule::SetHandler,
2847
                        response),
2848
      &error);
2849
  return error;
×
2850
}
×
2851

2852

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

2872

2873
/**
2874
 * @brief Set the tilt invert.
2875
 */
2876
string RDMHTTPModule::SetTiltInvert(const HTTPRequest *request,
×
2877
                                    HTTPResponse *response,
2878
                                    unsigned int universe_id,
2879
                                    const UID &uid) {
2880
  string mode = request->GetParameter(GENERIC_BOOL_FIELD);
×
2881
  string error;
×
2882
  m_rdm_api.SetTiltInvert(
×
2883
      universe_id,
2884
      uid,
2885
      ola::rdm::ROOT_RDM_DEVICE,
2886
      mode == "1",
×
2887
      NewSingleCallback(this,
2888
                        &RDMHTTPModule::SetHandler,
2889
                        response),
2890
      &error);
2891
  return error;
×
2892
}
×
2893

2894

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

2914

2915
/**
2916
 * @brief Set the pan/tilt swap.
2917
 */
2918
string RDMHTTPModule::SetPanTiltSwap(const HTTPRequest *request,
×
2919
                                     HTTPResponse *response,
2920
                                     unsigned int universe_id,
2921
                                     const UID &uid) {
2922
  string mode = request->GetParameter(GENERIC_BOOL_FIELD);
×
2923
  string error;
×
2924
  m_rdm_api.SetPanTiltSwap(
×
2925
      universe_id,
2926
      uid,
2927
      ola::rdm::ROOT_RDM_DEVICE,
2928
      mode == "1",
×
2929
      NewSingleCallback(this,
2930
                        &RDMHTTPModule::SetHandler,
2931
                        response),
2932
      &error);
2933
  return error;
×
2934
}
×
2935

2936

2937
/**
2938
 * @brief Handle the request for the clock section.
2939
 */
2940
string RDMHTTPModule::GetClock(HTTPResponse *response,
×
2941
                               unsigned int universe_id,
2942
                               const UID &uid) {
2943
  string error;
×
2944
  m_rdm_api.GetClock(
×
2945
      universe_id,
2946
      uid,
2947
      ola::rdm::ROOT_RDM_DEVICE,
2948
      NewSingleCallback(this,
2949
                        &RDMHTTPModule::ClockHandler,
2950
                        response),
2951
      &error);
2952
  return error;
×
2953
}
×
2954

2955

2956
/**
2957
 * @brief Handle the response to clock call and build the response
2958
 */
2959
void RDMHTTPModule::ClockHandler(HTTPResponse *response,
×
2960
                                 const ola::rdm::ResponseStatus &status,
2961
                                 const ola::rdm::ClockValue &clock) {
2962
  if (CheckForRDMError(response, status)) {
×
2963
    return;
×
2964
  }
2965

2966
  JsonSection section;
×
2967
  ostringstream str;
×
2968
  str << std::setfill('0') << std::setw(2) << static_cast<int>(clock.hour)
×
2969
      << ":" << std::setw(2) << static_cast<int>(clock.minute) << ":"
×
2970
      << std::setw(2) << static_cast<int>(clock.second) << " "
×
2971
      << static_cast<int>(clock.day) << "/" << static_cast<int>(clock.month)
×
2972
      << "/" << clock.year;
×
2973

2974
  section.AddItem(new StringItem("Clock", str.str()));
×
2975
  section.AddItem(new HiddenItem("1", GENERIC_UINT_FIELD));
×
2976
  section.SetSaveButton("Sync to Server");
×
2977
  RespondWithSection(response, section);
×
2978
}
×
2979

2980

2981
/**
2982
 * @brief Sync the clock
2983
 */
2984
string RDMHTTPModule::SyncClock(HTTPResponse *response,
×
2985
                                unsigned int universe_id,
2986
                                const UID &uid) {
2987
  time_t now = time(NULL);
×
2988
  struct tm now_tm;
×
2989
#ifdef _WIN32
2990
  memcpy(&now_tm, localtime(&now), sizeof(now_tm));
2991
#else
2992
  localtime_r(&now, &now_tm);
×
2993
#endif  // _WIN32
2994
  ola::rdm::ClockValue clock_value;
×
2995

2996
  clock_value.year = now_tm.tm_year + 1900;
×
2997
  clock_value.month = now_tm.tm_mon + 1;
×
2998
  clock_value.day = now_tm.tm_mday;
×
2999
  clock_value.hour = now_tm.tm_hour;
×
3000
  clock_value.minute = now_tm.tm_min;
×
3001
  clock_value.second = now_tm.tm_sec;
×
3002
  string error;
×
3003
  m_rdm_api.SetClock(
×
3004
      universe_id,
3005
      uid,
3006
      ola::rdm::ROOT_RDM_DEVICE,
3007
      clock_value,
3008
      NewSingleCallback(this,
3009
                        &RDMHTTPModule::SetHandler,
3010
                        response),
3011
      &error);
3012
  return error;
×
3013
}
×
3014

3015

3016
/**
3017
 * @brief Handle the request for the identify device section.
3018
 */
3019
string RDMHTTPModule::GetIdentifyDevice(HTTPResponse *response,
×
3020
                                        unsigned int universe_id,
3021
                                        const UID &uid) {
3022
  string error;
×
3023
  m_rdm_api.GetIdentifyDevice(
×
3024
      universe_id,
3025
      uid,
3026
      ola::rdm::ROOT_RDM_DEVICE,
3027
      NewSingleCallback(this,
3028
                        &RDMHTTPModule::GenericBoolHandler,
3029
                        response,
3030
                        string("Identify Device")),
×
3031
      &error);
3032
  return error;
×
3033
}
×
3034

3035

3036
/*
3037
 * @brief Set identify device
3038
 */
3039
string RDMHTTPModule::SetIdentifyDevice(const HTTPRequest *request,
×
3040
                                        HTTPResponse *response,
3041
                                        unsigned int universe_id,
3042
                                        const UID &uid) {
3043
  string mode = request->GetParameter(GENERIC_BOOL_FIELD);
×
3044
  string error;
×
3045
  m_rdm_api.IdentifyDevice(
×
3046
      universe_id,
3047
      uid,
3048
      ola::rdm::ROOT_RDM_DEVICE,
3049
      mode == "1",
×
3050
      NewSingleCallback(this,
3051
                        &RDMHTTPModule::SetHandler,
3052
                        response),
3053
      &error);
3054
  return error;
×
3055
}
×
3056

3057

3058
/**
3059
 * @brief Handle the request for the power state section.
3060
 */
3061
string RDMHTTPModule::GetPowerState(HTTPResponse *response,
×
3062
                                    unsigned int universe_id,
3063
                                    const UID &uid) {
3064
  string error;
×
3065
  m_rdm_api.GetPowerState(
×
3066
      universe_id,
3067
      uid,
3068
      ola::rdm::ROOT_RDM_DEVICE,
3069
      NewSingleCallback(this,
3070
                        &RDMHTTPModule::PowerStateHandler,
3071
                        response),
3072
      &error);
3073
  return error;
×
3074
}
×
3075

3076

3077
/**
3078
 * @brief Handle the response to power state call and build the response
3079
 */
3080
void RDMHTTPModule::PowerStateHandler(HTTPResponse *response,
×
3081
                                      const ola::rdm::ResponseStatus &status,
3082
                                      uint8_t value) {
3083
  if (CheckForRDMError(response, status)) {
×
3084
    return;
×
3085
  }
3086

3087
  JsonSection section;
×
3088
  SelectItem *item = new SelectItem("Power State", GENERIC_UINT_FIELD);
×
3089

3090
  typedef struct {
×
3091
    string label;
3092
    ola::rdm::rdm_power_state state;
3093
  } values_s;
×
3094

3095
  values_s possible_values[] = {
×
3096
    {"Full Off", ola::rdm::POWER_STATE_FULL_OFF},
×
3097
    {"Shutdown", ola::rdm::POWER_STATE_SHUTDOWN},
3098
    {"Standby", ola::rdm::POWER_STATE_STANDBY},
3099
    {"Normal", ola::rdm::POWER_STATE_NORMAL}};
×
3100

3101
  for (unsigned int i = 0; i < sizeof(possible_values) / sizeof(values_s);
×
3102
       ++i) {
3103
    item->AddItem(possible_values[i].label, possible_values[i].state);
×
3104
    if (value == possible_values[i].state) {
×
3105
      item->SetSelectedOffset(i);
×
3106
    }
3107
  }
3108

3109
  section.AddItem(item);
×
3110
  RespondWithSection(response, section);
×
3111
}
×
3112

3113

3114
/*
3115
 * @brief Set the power state.
3116
 */
3117
string RDMHTTPModule::SetPowerState(const HTTPRequest *request,
×
3118
                                    HTTPResponse *response,
3119
                                    unsigned int universe_id,
3120
                                    const UID &uid) {
3121
  string power_state_str = request->GetParameter(GENERIC_UINT_FIELD);
×
3122
  uint8_t power_state;
×
3123
  ola::rdm::rdm_power_state power_state_enum;
×
3124
  if (!StringToInt(power_state_str, &power_state) ||
×
3125
      !ola::rdm::UIntToPowerState(power_state, &power_state_enum)) {
×
3126
    return "Invalid power state";
×
3127
  }
3128

3129
  string error;
×
3130
  m_rdm_api.SetPowerState(
×
3131
      universe_id,
3132
      uid,
3133
      ola::rdm::ROOT_RDM_DEVICE,
3134
      power_state_enum,
3135
      NewSingleCallback(this,
3136
                        &RDMHTTPModule::SetHandler,
3137
                        response),
3138
      &error);
3139
  return error;
×
3140
}
×
3141

3142

3143
/**
3144
 * @brief Handle the request for the device reset section.
3145
 */
3146
string RDMHTTPModule::GetResetDevice(HTTPResponse *response) {
×
3147
  JsonSection section = JsonSection(false);
×
3148
  SelectItem *item = new SelectItem("Reset Device", GENERIC_UINT_FIELD);
×
3149

3150
  typedef struct {
×
3151
    string label;
3152
    ola::rdm::rdm_reset_device_mode state;
3153
  } values_s;
×
3154

3155
  values_s possible_values[] = {
×
3156
    {"Warm Reset", ola::rdm::RESET_WARM},
×
3157
    {"Cold Reset", ola::rdm::RESET_COLD}};
×
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
  }
3163

3164
  section.AddItem(item);
×
3165
  section.SetSaveButton("Reset Device");
×
3166
  RespondWithSection(response, section);
×
3167

3168
  return "";
×
3169
}
×
3170

3171

3172
/*
3173
 * @brief Set the reset device.
3174
 */
3175
string RDMHTTPModule::SetResetDevice(const HTTPRequest *request,
×
3176
                                     HTTPResponse *response,
3177
                                     unsigned int universe_id,
3178
                                     const UID &uid) {
3179
  string reset_device_str = request->GetParameter(GENERIC_UINT_FIELD);
×
3180
  uint8_t reset_device;
×
3181
  ola::rdm::rdm_reset_device_mode reset_device_enum;
×
3182
  if (!StringToInt(reset_device_str, &reset_device) ||
×
3183
      !ola::rdm::UIntToResetDevice(reset_device, &reset_device_enum)) {
×
3184
    return "Invalid reset device";
×
3185
  }
3186

3187
  string error;
×
3188
  m_rdm_api.SetResetDevice(
×
3189
      universe_id,
3190
      uid,
3191
      ola::rdm::ROOT_RDM_DEVICE,
3192
      reset_device_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 DNS Hostname.
3203
 */
3204
string RDMHTTPModule::GetDnsHostname(HTTPResponse *response,
×
3205
                                     unsigned int universe_id,
3206
                                     const UID &uid) {
3207
  string error;
×
3208
  m_rdm_api.GetDnsHostname(
×
3209
      universe_id,
3210
      uid,
3211
      ola::rdm::ROOT_RDM_DEVICE,
3212
      NewSingleCallback(this,
3213
                        &RDMHTTPModule::GetDnsHostnameHandler,
3214
                        response),
3215
      &error);
3216
  return error;
×
3217
}
×
3218

3219

3220
/**
3221
 * @brief Handle the response to a DNS hostname call and build the response
3222
 */
3223
void RDMHTTPModule::GetDnsHostnameHandler(
×
3224
    HTTPResponse *response,
3225
    const ola::rdm::ResponseStatus &status,
3226
    const string &label) {
3227
  if (CheckForRDMError(response, status)) {
×
3228
    return;
×
3229
  }
3230

3231
  JsonSection section;
×
3232
  section.AddItem(new StringItem("Hostname", label, GENERIC_STRING_FIELD));
×
3233
  RespondWithSection(response, section);
×
3234
}
×
3235

3236

3237
/*
3238
 * @brief Set the DNS hostname
3239
 */
3240
string RDMHTTPModule::SetDnsHostname(const HTTPRequest *request,
×
3241
                                     HTTPResponse *response,
3242
                                     unsigned int universe_id,
3243
                                     const UID &uid) {
3244
  string label = request->GetParameter(GENERIC_STRING_FIELD);
×
3245
  string error;
×
3246
  m_rdm_api.SetDnsHostname(
×
3247
      universe_id,
3248
      uid,
3249
      ola::rdm::ROOT_RDM_DEVICE,
3250
      label,
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 domain name.
3261
 */
3262
string RDMHTTPModule::GetDnsDomainName(HTTPResponse *response,
×
3263
                                       unsigned int universe_id,
3264
                                       const UID &uid) {
3265
  string error;
×
3266
  m_rdm_api.GetDnsDomainName(
×
3267
      universe_id,
3268
      uid,
3269
      ola::rdm::ROOT_RDM_DEVICE,
3270
      NewSingleCallback(this,
3271
                        &RDMHTTPModule::GetDnsDomainNameHandler,
3272
                        response),
3273
      &error);
3274
  return error;
×
3275
}
×
3276

3277

3278
/**
3279
 * @brief Handle the response to a DNS domain name call and build the response
3280
 */
3281
void RDMHTTPModule::GetDnsDomainNameHandler(
×
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("Domain Name", label, GENERIC_STRING_FIELD));
×
3291
  RespondWithSection(response, section);
×
3292
}
×
3293

3294

3295
/*
3296
 * @brief Set the DNS domain name
3297
 */
3298
string RDMHTTPModule::SetDnsDomainName(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.SetDnsDomainName(
×
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 Check if the id URL param exists and is valid.
3319
 */
3320
bool RDMHTTPModule::CheckForInvalidId(const HTTPRequest *request,
×
3321
                                      unsigned int *universe_id) {
3322
  string uni_id = request->GetParameter(ID_KEY);
×
3323
  if (!StringToInt(uni_id, universe_id)) {
×
3324
    OLA_INFO << "Invalid universe id: " << uni_id;
×
3325
    return false;
×
3326
  }
3327
  return true;
3328
}
×
3329

3330

3331
/**
3332
 * @brief Check that the uid URL param exists and is valid.
3333
 */
3334
bool RDMHTTPModule::CheckForInvalidUid(const HTTPRequest *request,
×
3335
                                       UID **uid) {
3336
  string uid_string = request->GetParameter(UID_KEY);
×
3337
  *uid = UID::FromString(uid_string);
×
3338
  if (*uid == NULL) {
×
3339
    OLA_INFO << "Invalid UID: " << uid_string;
×
3340
    return false;
×
3341
  }
3342
  return true;
3343
}
×
3344

3345

3346
/**
3347
 * @brief Get the sub device from the HTTP request, or return ROOT_DEVICE if it
3348
 *   isn't valid.
3349
 */
3350
uint16_t RDMHTTPModule::SubDeviceOrRoot(const HTTPRequest *request) {
×
3351
  string sub_device_str = request->GetParameter(SUB_DEVICE_FIELD);
×
3352
  uint16_t sub_device;
×
3353

3354
  if (StringToInt(sub_device_str, &sub_device)) {
×
3355
    return sub_device;
×
3356
  }
3357

3358
  OLA_INFO << "Invalid sub device " << sub_device_str;
×
3359
  return ola::rdm::ROOT_RDM_DEVICE;
×
3360
}
×
3361

3362

3363
/*
3364
 * @brief Check the response to a Set RDM call and build the response.
3365
 */
3366
void RDMHTTPModule::SetHandler(
×
3367
    HTTPResponse *response,
3368
    const ola::rdm::ResponseStatus &status) {
3369
  string error;
×
3370
  CheckForRDMSuccessWithError(status, &error);
×
3371
  RespondWithError(response, error);
×
3372
}
×
3373

3374

3375
/*
3376
 * @brief Build a response to a RDM call that returns a uint32_t
3377
 */
3378
void RDMHTTPModule::GenericUIntHandler(HTTPResponse *response,
×
3379
                                       string description,
3380
                                       const ola::rdm::ResponseStatus &status,
3381
                                       uint32_t value) {
3382
  if (CheckForRDMError(response, status)) {
×
3383
    return;
×
3384
  }
3385

3386
  JsonSection section;
×
3387
  section.AddItem(new UIntItem(description, value, GENERIC_UINT_FIELD));
×
3388
  RespondWithSection(response, section);
×
3389
}
×
3390

3391

3392
/*
3393
 * @brief Build a response to a RDM call that returns a bool
3394
 */
3395
void RDMHTTPModule::GenericUInt8BoolHandler(
×
3396
    HTTPResponse *response,
3397
    string description,
3398
    const ola::rdm::ResponseStatus &status,
3399
    uint8_t value) {
3400
  GenericBoolHandler(response, description, status, value > 0);
×
3401
}
×
3402

3403

3404
/*
3405
 * @brief Build a response to a RDM call that returns a bool
3406
 */
3407
void RDMHTTPModule::GenericBoolHandler(HTTPResponse *response,
×
3408
                                       string description,
3409
                                       const ola::rdm::ResponseStatus &status,
3410
                                       bool value) {
3411
  if (CheckForRDMError(response, status)) {
×
3412
    return;
×
3413
  }
3414

3415
  JsonSection section;
×
3416
  section.AddItem(new BoolItem(description, value, GENERIC_BOOL_FIELD));
×
3417
  RespondWithSection(response, section);
×
3418
}
×
3419

3420
/**
3421
 * @brief Check for an RDM error, and if it occurs, return a JSON response.
3422
 * @return true if an error occurred.
3423
 */
3424
bool RDMHTTPModule::CheckForRDMError(HTTPResponse *response,
×
3425
                                     const ola::rdm::ResponseStatus &status) {
3426
  string error;
×
3427
  if (!CheckForRDMSuccessWithError(status, &error)) {
×
3428
    RespondWithError(response, error);
×
3429
    return true;
3430
  }
3431
  return false;
3432
}
×
3433

3434

3435

3436
int RDMHTTPModule::RespondWithError(HTTPResponse *response,
×
3437
                                    const string &error) {
3438
  response->SetNoCache();
×
3439
  response->SetContentType(HTTPServer::CONTENT_TYPE_PLAIN);
×
3440

3441
  JsonObject json;
×
3442
  json.Add("error", error);
×
3443
  int r = response->SendJson(json);
×
3444
  delete response;
×
3445
  return r;
×
3446
}
×
3447

3448

3449
/**
3450
 * @brief Build & send a response from a JsonSection
3451
 */
3452
void RDMHTTPModule::RespondWithSection(HTTPResponse *response,
×
3453
                                       const ola::web::JsonSection &section) {
3454
  response->SetNoCache();
×
3455
  response->SetContentType(HTTPServer::CONTENT_TYPE_PLAIN);
×
3456
  response->Append(section.AsString());
×
3457
  response->Send();
×
3458
  delete response;
×
3459
}
×
3460

3461

3462
/*
3463
 * @brief Check the success of an RDM command
3464
 * @returns true if this command was ok, false otherwise.
3465
 */
3466
bool RDMHTTPModule::CheckForRDMSuccess(
×
3467
    const ola::rdm::ResponseStatus &status) {
3468
  string error;
×
3469
  if (!CheckForRDMSuccessWithError(status, &error)) {
×
3470
    OLA_INFO << error;
×
3471
    return false;
×
3472
  }
3473
  return true;
3474
}
×
3475

3476

3477
/*
3478
 * @brief Check the success of an RDM command or return an error message.
3479
 *
3480
 * At the moment we're very strict in this method, some day this should be
3481
 * relaxed to handle the corner cases.
3482
 * @returns true if this command returns an ACK. false for any other condition.
3483
 */
3484
bool RDMHTTPModule::CheckForRDMSuccessWithError(
×
3485
    const ola::rdm::ResponseStatus &status,
3486
    string *error) {
3487
  ostringstream str;
×
3488
  if (!status.error.empty()) {
×
3489
    str << "RDM command error: " << status.error;
×
3490
    if (error) {
×
3491
      *error = str.str();
×
3492
    }
3493
    return false;
×
3494
  }
3495

3496
  // TODO(simon): One day we should handle broadcast responses, ack timers etc.
3497
  if (status.response_code != ola::rdm::RDM_COMPLETED_OK) {
×
3498
    if (error) {
×
3499
      *error = ola::rdm::StatusCodeToString(status.response_code);
×
3500
    }
3501
  } else {
3502
    switch (status.response_type) {
×
3503
      case ola::rdm::RDM_ACK:
3504
        return true;
3505
      case ola::rdm::RDM_ACK_TIMER:
×
3506
        str << "Got ACK Timer for " << status.AckTimer() << " ms";
×
3507
        if (error) {
×
3508
          *error = str.str();
×
3509
        }
3510
        break;
3511
      case ola::rdm::RDM_NACK_REASON:
×
3512
        str << "Request was NACKED with code: " <<
×
3513
          ola::rdm::NackReasonToString(status.NackReason());
×
3514
        OLA_INFO << str.str();
×
3515
        if (error) {
×
3516
          *error = str.str();
×
3517
        }
3518
    }
3519
  }
3520
  return false;
3521
}
×
3522

3523

3524
/*
3525
 * @brief Handle the RDM discovery response
3526
 * @param response the HTTPResponse that is associated with the request.
3527
 * @param error an error string.
3528
 */
3529
void RDMHTTPModule::HandleBoolResponse(HTTPResponse *response,
×
3530
                                       const string &error) {
3531
  if (!error.empty()) {
×
3532
    m_server->ServeError(response, error);
×
3533
    return;
×
3534
  }
3535
  response->SetNoCache();
×
3536
  response->SetContentType(HTTPServer::CONTENT_TYPE_PLAIN);
×
3537
  response->Append("ok");
×
3538
  response->Send();
×
3539
  delete response;
×
3540
}
3541

3542

3543
/**
3544
 * @brief Add a section to the supported section list
3545
 */
3546
void RDMHTTPModule::AddSection(vector<section_info> *sections,
×
3547
                               const string &section_id,
3548
                               const string &section_name,
3549
                               const string &hint) {
3550
  section_info info = {section_id, section_name, hint};
×
3551
  sections->push_back(info);
×
3552
}
×
3553
}  // 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