Open Lighting Architecture  Latest Git
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15  *
16  * ResponderOpsPrivate.h
17  * 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>
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>
49 ResponderOps<Target>::ResponderOps(const ParamHandler param_handlers[],
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 
76  if (!on_complete) {
77  OLA_WARN << "Null callback passed!";
78  return;
79  }
80 
81  // If this isn't directed to our UID (unicast, vendorcast or broadcast), we
82  // return early.
83  if (!request->DestinationUID().DirectedToUID(target_uid)) {
84  if (!request->DestinationUID().IsBroadcast()) {
85  OLA_WARN << "Received request for the wrong UID, "
86  << "expected " << target_uid << ", got "
87  << request->DestinationUID();
88  }
89 
91  on_complete,
92  request->DestinationUID().IsBroadcast() ? RDM_WAS_BROADCAST :
93  RDM_TIMEOUT);
94  return;
95  }
96 
97  // Right now we don't support discovery.
98  if (request->CommandClass() == RDMCommand::DISCOVER_COMMAND) {
99  RunRDMCallback(on_complete, RDM_PLUGIN_DISCOVERY_NOT_SUPPORTED);
100  return;
101  }
102 
103  // broadcast GETs are noops.
104  if (request->CommandClass() == RDMCommand::GET_COMMAND &&
105  request->DestinationUID().IsBroadcast()) {
106  OLA_WARN << "Received broadcast GET command";
107  RunRDMCallback(on_complete, RDM_WAS_BROADCAST);
108  return;
109  }
110 
111  RDMResponse *response = NULL;
112  RDMStatusCode status_code = RDM_COMPLETED_OK;
113 
114  // Right now we don't support sub devices
115  bool for_our_subdevice = request->SubDevice() == sub_device ||
116  request->SubDevice() == ALL_RDM_SUBDEVICES;
117 
118  if (!for_our_subdevice) {
119  if (request->DestinationUID().IsBroadcast()) {
120  RunRDMCallback(on_complete, RDM_WAS_BROADCAST);
121  } else {
122  RDMReply reply(RDM_COMPLETED_OK,
123  NackWithReason(request.get(), NR_SUB_DEVICE_OUT_OF_RANGE));
124  on_complete->Run(&reply);
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  RDMReply reply(RDM_COMPLETED_OK,
134  NackWithReason(request.get(), NR_SUB_DEVICE_OUT_OF_RANGE));
135  on_complete->Run(&reply);
136  return;
137  }
138 
139  InternalParamHandler *handler = STLFind(&m_handlers, request->ParamId());
140  if (!handler) {
141  if (request->DestinationUID().IsBroadcast()) {
142  RunRDMCallback(on_complete, RDM_WAS_BROADCAST);
143  } else {
144  RDMReply reply(RDM_COMPLETED_OK,
145  NackWithReason(request.get(), NR_UNKNOWN_PID));
146  on_complete->Run(&reply);
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  status_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  RunRDMCallback(on_complete, RDM_WAS_BROADCAST);
182  } else {
183  RDMReply reply(status_code, response);
184  on_complete->Run(&reply);
185  }
186 }
187 
188 template <class Target>
190  const RDMRequest *request) {
191  if (request->ParamDataSize())
192  return NackWithReason(request, NR_FORMAT_ERROR);
193 
194  std::vector<uint16_t> params;
195  params.reserve(m_handlers.size());
196  typename RDMHandlers::const_iterator iter = m_handlers.begin();
197  for (; iter != m_handlers.end(); ++iter) {
198  uint16_t pid = iter->first;
199  // some pids never appear in supported_parameters.
200  if (m_include_required_pids || (
201  pid != PID_SUPPORTED_PARAMETERS &&
202  pid != PID_PARAMETER_DESCRIPTION &&
203  pid != PID_DEVICE_INFO &&
204  pid != PID_SOFTWARE_VERSION_LABEL &&
205  pid != PID_DMX_START_ADDRESS &&
206  pid != PID_IDENTIFY_DEVICE)) {
207  params.push_back(iter->first);
208  }
209  }
210  sort(params.begin(), params.end());
211 
212  std::vector<uint16_t>::iterator param_iter = params.begin();
213  for (; param_iter != params.end(); ++param_iter) {
214  *param_iter = ola::network::HostToNetwork(*param_iter);
215  }
216 
217  return GetResponseFromData(
218  request,
219  reinterpret_cast<uint8_t*>(&params[0]),
220  params.size() * sizeof(uint16_t));
221 }
222 } // namespace rdm
223 } // namespace ola
224 #endif // INCLUDE_OLA_RDM_RESPONDEROPSPRIVATE_H_
Definitions and Interfaces to implement an RDMController that sends a single message at a time...
unsigned int ParamDataSize() const
Returns the Size of the Parameter Data of the RDMCommand.
Definition: RDMCommand.h:140
RDMStatusCode
RDM Status Codes.
Definition: RDMResponseCodes.h:45
uint16_t HostToNetwork(uint16_t value)
16-bit unsigned host to network conversion.
Definition: NetworkUtils.cpp:159
An RDM Command that represents responses (GET, SET or DISCOVER).
Definition: RDMCommand.h:457
RDMResponse * GetResponseFromData(const RDMRequest *request, const uint8_t *data, unsigned int length, rdm_response_type type, uint8_t outstanding_messages)
Generate an ACK Response with some data.
Definition: RDMCommand.cpp:595
RDM Commands that represent requests (GET, SET or DISCOVER).
Definition: RDMCommand.h:234
RDMResponse * NackWithReason(const RDMRequest *request, rdm_nack_reason reason_enum, uint8_t outstanding_messages)
Generate a NACK response with a reason code.
Definition: RDMCommand.cpp:583
#define OLA_WARN
Definition: Logging.h:75
Definition: RDMEnums.h:58
Definition: RDMEnums.h:56
Enums representing the states of a response. This is generated from the proto file.
A class which dispatches RDM requests to registered PID handlers.
Definition: ResponderOps.h:60
ResponderOps(const ParamHandler param_handlers[], bool include_required_pids=false)
Construct a new ResponderOps object.
Definition: ResponderOpsPrivate.h:49
The base class for all 1 argument callbacks.
Definition: Callback.h:982
Helper functions for STL classes.
Holds the final state of an RDM request.
Definition: RDMReply.h:43
Definition: RDMEnums.h:60
void RunRDMCallback(RDMCallback *callback, RDMStatusCode status_code)
A helper message to run a RDMCallback with the given status code.
Definition: RDMControllerInterface.h:59
Represents a RDM UID.
Definition: UID.h:57
bool STLReplace(T1 *container, const typename T1::key_type &key, const typename T1::mapped_type &value)
Replace a value in a pair associative container, inserting the key, value if it doesn&#39;t already exist...
Definition: STLUtils.h:258
The namespace containing all OLA symbols.
Definition: Credentials.cpp:44
T1::mapped_type * STLFind(T1 *container, const typename T1::key_type &key)
Lookup a value by key in a associative container.
Definition: STLUtils.h:193
Header file for OLA Logging.
Classes that represent RDM commands.