Open Lighting Architecture  0.9.0
 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 template <class Target>
50  bool include_required_pids)
51  : m_include_required_pids(include_required_pids) {
52  // We install placeholders for any pids which are handled internally.
53  struct InternalParamHandler placeholder = {NULL, NULL};
54  STLReplace(&m_handlers, PID_SUPPORTED_PARAMETERS, placeholder);
55 
56  const ParamHandler *handler = param_handlers;
57  while (handler->pid && (handler->get_handler || handler->set_handler)) {
58  struct InternalParamHandler pid_handler = {
59  handler->get_handler,
60  handler->set_handler
61  };
62  STLReplace(&m_handlers, handler->pid, pid_handler);
63  handler++;
64  }
65 }
66 
67 template <class Target>
69  const UID &target_uid,
70  uint16_t sub_device,
71  const RDMRequest *raw_request,
72  RDMCallback *on_complete) {
73  // Take ownership of the request object, so the targets don't have to.
74  std::auto_ptr<const RDMRequest> request(raw_request);
75  std::vector<std::string> packets;
76 
77  if (!on_complete) {
78  OLA_WARN << "Null callback passed!";
79  return;
80  }
81 
82  // If this isn't directed to our UID (unicast, vendorcast or broadcast), we
83  // return early.
84  if (!request->DestinationUID().DirectedToUID(target_uid)) {
85  if (!request->DestinationUID().IsBroadcast()) {
86  OLA_WARN << "Received request for the wrong UID, "
87  << "expected " << target_uid << ", got "
88  << request->DestinationUID();
89  }
90 
91  on_complete->Run(
92  (request->DestinationUID().IsBroadcast() ?
93  RDM_WAS_BROADCAST : RDM_TIMEOUT),
94  NULL, packets);
95  return;
96  }
97 
98  // Right now we don't support discovery.
99  if (request->CommandClass() == RDMCommand::DISCOVER_COMMAND) {
100  on_complete->Run(RDM_PLUGIN_DISCOVERY_NOT_SUPPORTED, NULL, packets);
101  return;
102  }
103 
104  // broadcast GETs are noops.
105  if (request->CommandClass() == RDMCommand::GET_COMMAND &&
106  request->DestinationUID().IsBroadcast()) {
107  OLA_WARN << "Received broadcast GET command";
108  on_complete->Run(RDM_WAS_BROADCAST, NULL, packets);
109  return;
110  }
111 
112  const RDMResponse *response = NULL;
113  rdm_response_code response_code = RDM_COMPLETED_OK;
114 
115  // Right now we don't support sub devices
116  bool for_our_subdevice = request->SubDevice() == sub_device ||
117  request->SubDevice() == ALL_RDM_SUBDEVICES;
118 
119  if (!for_our_subdevice) {
120  if (request->DestinationUID().IsBroadcast()) {
121  on_complete->Run(RDM_WAS_BROADCAST, NULL, packets);
122  } else {
123  response = NackWithReason(request.get(), NR_SUB_DEVICE_OUT_OF_RANGE);
124  on_complete->Run(RDM_COMPLETED_OK, response, packets);
125  }
126  return;
127  }
128 
129  // gets to ALL_RDM_SUBDEVICES are a special case
130  if (request->SubDevice() == ALL_RDM_SUBDEVICES &&
131  request->CommandClass() == RDMCommand::GET_COMMAND) {
132  // the broadcast get case was handled above.
133  response = NackWithReason(request.get(), NR_SUB_DEVICE_OUT_OF_RANGE);
134  on_complete->Run(RDM_COMPLETED_OK, response, packets);
135  return;
136  }
137 
138  InternalParamHandler *handler = STLFind(&m_handlers, request->ParamId());
139  if (!handler) {
140  if (request->DestinationUID().IsBroadcast()) {
141  on_complete->Run(RDM_WAS_BROADCAST, NULL, packets);
142  } else {
143  response = NackWithReason(request.get(), NR_UNKNOWN_PID);
144  on_complete->Run(RDM_COMPLETED_OK, response, packets);
145  }
146  return;
147  }
148 
149  if (request->CommandClass() == RDMCommand::GET_COMMAND) {
150  if (request->DestinationUID().IsBroadcast()) {
151  // this should have been handled above, but be safe.
152  response_code = RDM_WAS_BROADCAST;
153  } else {
154  if (handler->get_handler) {
155  response = (target->*(handler->get_handler))(request.get());
156  } else {
157  switch (request->ParamId()) {
158  case PID_SUPPORTED_PARAMETERS:
159  response = HandleSupportedParams(request.get());
160  break;
161  default:
162  response = NackWithReason(request.get(),
163  NR_UNSUPPORTED_COMMAND_CLASS);
164  }
165  }
166  }
167  } else if (request->CommandClass() == RDMCommand::SET_COMMAND) {
168  if (handler->set_handler) {
169  response = (target->*(handler->set_handler))(request.get());
170  } else {
171  response = NackWithReason(request.get(), NR_UNSUPPORTED_COMMAND_CLASS);
172  }
173  }
174 
175  if (request->DestinationUID().IsBroadcast()) {
176  if (response) {
177  delete response;
178  }
179  on_complete->Run(RDM_WAS_BROADCAST, NULL, packets);
180  } else {
181  on_complete->Run(response_code, response, packets);
182  }
183 }
184 
185 template <class Target>
187  const RDMRequest *request) {
188  if (request->ParamDataSize())
189  return NackWithReason(request, NR_FORMAT_ERROR);
190 
191  std::vector<uint16_t> params;
192  params.reserve(m_handlers.size());
193  typename RDMHandlers::const_iterator iter = m_handlers.begin();
194  for (; iter != m_handlers.end(); ++iter) {
195  uint16_t pid = iter->first;
196  // some pids never appear in supported_parameters.
197  if (m_include_required_pids || (
198  pid != PID_SUPPORTED_PARAMETERS &&
199  pid != PID_PARAMETER_DESCRIPTION &&
200  pid != PID_DEVICE_INFO &&
201  pid != PID_SOFTWARE_VERSION_LABEL &&
202  pid != PID_DMX_START_ADDRESS &&
203  pid != PID_IDENTIFY_DEVICE)) {
204  params.push_back(iter->first);
205  }
206  }
207  sort(params.begin(), params.end());
208 
209  std::vector<uint16_t>::iterator param_iter = params.begin();
210  for (; param_iter != params.end(); ++param_iter) {
211  *param_iter = ola::network::HostToNetwork(*param_iter);
212  }
213 
214  return GetResponseFromData(
215  request,
216  reinterpret_cast<uint8_t*>(&params[0]),
217  params.size() * sizeof(uint16_t));
218 }
219 } // namespace rdm
220 } // namespace ola
221 #endif // INCLUDE_OLA_RDM_RESPONDEROPSPRIVATE_H_