Open Lighting Architecture
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ResponderOpsPrivate.h
Go to the documentation of this file.
1 /*
2  * This library is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU Lesser General Public
4  * License as published by the Free Software Foundation; either
5  * version 2.1 of the License, or (at your option) any later version.
6  *
7  * This library is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10  * Lesser General Public License for more details.
11  *
12  * You should have received a copy of the GNU Lesser General Public
13  * License along with this library; if not, write to the Free Software
14  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15  *
16  * ResponderOpsPrivate.h
17  * A private helper functions for building RDM responders.
18  * Copyright (C) 2013 Simon Newton
19  */
20 
29 #ifndef INCLUDE_OLA_RDM_RESPONDEROPSPRIVATE_H_
30 #define INCLUDE_OLA_RDM_RESPONDEROPSPRIVATE_H_
31 
32 #include <ola/Logging.h>
33 #include <ola/network/NetworkUtils.h>
34 #include <ola/rdm/RDMCommand.h>
36 #include <ola/rdm/RDMResponseCodes.h>
37 #include <ola/stl/STLUtils.h>
38 
39 #include <algorithm>
40 #include <map>
41 #include <memory>
42 #include <string>
43 #include <vector>
44 
45 namespace ola {
46 namespace rdm {
47 
48 using std::auto_ptr;
49 
50 template <class Target>
52  bool include_required_pids)
53  : m_include_required_pids(include_required_pids) {
54  // We install placeholders for any pids which are handled internally.
55  struct InternalParamHandler placeholder = {NULL, NULL};
56  STLReplace(&m_handlers, PID_SUPPORTED_PARAMETERS, placeholder);
57 
58  const ParamHandler *handler = param_handlers;
59  while (handler->pid && (handler->get_handler || handler->set_handler)) {
60  struct InternalParamHandler pid_handler = {
61  handler->get_handler,
62  handler->set_handler
63  };
64  STLReplace(&m_handlers, handler->pid, pid_handler);
65  handler++;
66  }
67 }
68 
69 template <class Target>
71  const UID &target_uid,
72  uint16_t sub_device,
73  const RDMRequest *raw_request,
74  RDMCallback *on_complete) {
75  // Take ownership of the request object, so the targets don't have to.
76  auto_ptr<const RDMRequest> request(raw_request);
77  vector<string> packets;
78 
79  if (!on_complete) {
80  OLA_WARN << "Null callback passed!";
81  return;
82  }
83 
84  // If this isn't directed to our UID (unicast, vendorcast or broadcast), we
85  // return early.
86  if (!request->DestinationUID().DirectedToUID(target_uid)) {
87  if (!request->DestinationUID().IsBroadcast()) {
88  OLA_WARN << "Received request for the wrong UID, "
89  << "expected " << target_uid << ", got "
90  << request->DestinationUID();
91  }
92 
93  on_complete->Run(
94  (request->DestinationUID().IsBroadcast() ?
95  RDM_WAS_BROADCAST : RDM_TIMEOUT),
96  NULL, packets);
97  return;
98  }
99 
100  // Right now we don't support discovery.
101  if (request->CommandClass() == RDMCommand::DISCOVER_COMMAND) {
102  on_complete->Run(RDM_PLUGIN_DISCOVERY_NOT_SUPPORTED, NULL, packets);
103  return;
104  }
105 
106  // broadcast GETs are noops.
107  if (request->CommandClass() == RDMCommand::GET_COMMAND &&
108  request->DestinationUID().IsBroadcast()) {
109  OLA_WARN << "Received broadcast GET command";
110  on_complete->Run(RDM_WAS_BROADCAST, NULL, packets);
111  return;
112  }
113 
114  const RDMResponse *response = NULL;
115  rdm_response_code response_code = RDM_COMPLETED_OK;
116 
117  // Right now we don't support sub devices
118  bool for_our_subdevice = request->SubDevice() == sub_device ||
119  request->SubDevice() == ALL_RDM_SUBDEVICES;
120 
121  if (!for_our_subdevice) {
122  if (request->DestinationUID().IsBroadcast()) {
123  on_complete->Run(RDM_WAS_BROADCAST, NULL, packets);
124  } else {
125  response = NackWithReason(request.get(), NR_SUB_DEVICE_OUT_OF_RANGE);
126  on_complete->Run(RDM_COMPLETED_OK, response, packets);
127  }
128  return;
129  }
130 
131  // gets to ALL_RDM_SUBDEVICES are a special case
132  if (request->SubDevice() == ALL_RDM_SUBDEVICES &&
133  request->CommandClass() == RDMCommand::GET_COMMAND) {
134  // the broadcast get case was handled above.
135  response = NackWithReason(request.get(), NR_SUB_DEVICE_OUT_OF_RANGE);
136  on_complete->Run(RDM_COMPLETED_OK, response, packets);
137  return;
138  }
139 
140  InternalParamHandler *handler = STLFind(&m_handlers, request->ParamId());
141  if (!handler) {
142  if (request->DestinationUID().IsBroadcast()) {
143  on_complete->Run(RDM_WAS_BROADCAST, NULL, packets);
144  } else {
145  response = NackWithReason(request.get(), NR_UNKNOWN_PID);
146  on_complete->Run(RDM_COMPLETED_OK, response, packets);
147  }
148  return;
149  }
150 
151  if (request->CommandClass() == RDMCommand::GET_COMMAND) {
152  if (request->DestinationUID().IsBroadcast()) {
153  // this should have been handled above, but be safe.
154  response_code = RDM_WAS_BROADCAST;
155  } else {
156  if (handler->get_handler) {
157  response = (target->*(handler->get_handler))(request.get());
158  } else {
159  switch (request->ParamId()) {
160  case PID_SUPPORTED_PARAMETERS:
161  response = HandleSupportedParams(request.get());
162  break;
163  default:
164  response = NackWithReason(request.get(),
165  NR_UNSUPPORTED_COMMAND_CLASS);
166  }
167  }
168  }
169  } else if (request->CommandClass() == RDMCommand::SET_COMMAND) {
170  if (handler->set_handler) {
171  response = (target->*(handler->set_handler))(request.get());
172  } else {
173  response = NackWithReason(request.get(), NR_UNSUPPORTED_COMMAND_CLASS);
174  }
175  }
176 
177  if (request->DestinationUID().IsBroadcast()) {
178  if (response) {
179  delete response;
180  }
181  on_complete->Run(RDM_WAS_BROADCAST, NULL, packets);
182  } else {
183  on_complete->Run(response_code, response, packets);
184  }
185 }
186 
187 template <class Target>
189  const RDMRequest *request) {
190  if (request->ParamDataSize())
191  return NackWithReason(request, NR_FORMAT_ERROR);
192 
193  vector<uint16_t> params;
194  params.reserve(m_handlers.size());
195  typename RDMHandlers::const_iterator iter = m_handlers.begin();
196  for (; iter != m_handlers.end(); ++iter) {
197  uint16_t pid = iter->first;
198  // some pids never appear in supported_parameters.
199  if (m_include_required_pids || (
200  pid != PID_SUPPORTED_PARAMETERS &&
201  pid != PID_PARAMETER_DESCRIPTION &&
202  pid != PID_DEVICE_INFO &&
203  pid != PID_SOFTWARE_VERSION_LABEL &&
204  pid != PID_DMX_START_ADDRESS &&
205  pid != PID_IDENTIFY_DEVICE)) {
206  params.push_back(iter->first);
207  }
208  }
209  sort(params.begin(), params.end());
210 
211  vector<uint16_t>::iterator param_iter = params.begin();
212  for (; param_iter != params.end(); ++param_iter) {
213  *param_iter = ola::network::HostToNetwork(*param_iter);
214  }
215 
216  return GetResponseFromData(
217  request,
218  reinterpret_cast<uint8_t*>(&params[0]),
219  params.size() * sizeof(uint16_t));
220 }
221 } // namespace rdm
222 } // namespace ola
223 #endif // INCLUDE_OLA_RDM_RESPONDEROPSPRIVATE_H_