Open Lighting Architecture 0.10.9
Loading...
Searching...
No Matches
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
45namespace ola {
46namespace rdm {
47
48template <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
67template <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;
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
188template <class Target>
189RDMResponse *ResponderOps<Target>::HandleSupportedParams(
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_
Header file for OLA Logging.
Classes that represent RDM commands.
Definitions and Interfaces to implement an RDMController that sends a single message at a time.
Enums representing the states of a response. This is generated from the proto file.
Helper functions for STL classes.
The base class for all 1 argument callbacks.
Definition Callback.h:982
@ GET_COMMAND
Definition RDMCommand.h:69
@ SET_COMMAND
Definition RDMCommand.h:71
@ DISCOVER_COMMAND
Definition RDMCommand.h:67
RDM Commands that represent requests (GET, SET or DISCOVER).
Definition RDMCommand.h:234
An RDM Command that represents responses (GET, SET or DISCOVER).
Definition RDMCommand.h:457
ResponderOps(const ParamHandler param_handlers[], bool include_required_pids=false)
Construct a new ResponderOps object.
Definition ResponderOpsPrivate.h:49
void HandleRDMRequest(Target *target, const UID &target_uid, uint16_t sub_device, const RDMRequest *request, RDMCallback *on_complete)
Handle a RDMRequest.
Definition ResponderOpsPrivate.h:68
Represents a RDM UID.
Definition UID.h:57
#define OLA_WARN
Definition Logging.h:73
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:584
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:572
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
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't already exist...
Definition STLUtils.h:258
uint16_t HostToNetwork(uint16_t value)
16-bit unsigned host to network conversion.
Definition NetworkUtils.cpp:159
void RunRDMCallback(RDMCallback *callback, RDMStatusCode status_code)
A helper message to run a RDMCallback with the given status code.
Definition RDMControllerInterface.h:59
RDMStatusCode
RDM Status Codes.
Definition RDMResponseCodes.h:45
The namespace containing all OLA symbols.
Definition Credentials.cpp:44
the structure that defines the behaviour for a specific PID.o
Definition ResponderOps.h:76
uint16_t pid
Definition ResponderOps.h:77
RDMHandler get_handler
Definition ResponderOps.h:78
RDMHandler set_handler
Definition ResponderOps.h:79