Open Lighting Architecture  0.9.6
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ResponderSettings.h
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  * ResponderSettings.h
17  * Copyright (C) 2013 Simon Newton
18  */
19 
20 #ifndef INCLUDE_OLA_RDM_RESPONDERSETTINGS_H_
21 #define INCLUDE_OLA_RDM_RESPONDERSETTINGS_H_
22 
23 #include <ola/base/Macro.h>
24 #include <ola/rdm/RDMCommand.h>
26 #include <stdint.h>
27 #include <string>
28 #include <vector>
29 
30 namespace ola {
31 namespace rdm {
32 
37  public:
38  virtual ~SettingInterface() {}
39 
44  virtual std::string Description() const = 0;
45 
49  virtual unsigned int DescriptionResponseSize() const = 0;
50 
56  virtual unsigned int GenerateDescriptionResponse(uint8_t index,
57  uint8_t *data) const = 0;
58 };
59 
64  public:
65  typedef const char* ArgType;
66 
71  explicit BasicSetting(const ArgType description);
72 
77  std::string Description() const { return m_description; }
78 
79  unsigned int DescriptionResponseSize() const {
80  return sizeof(description_s);
81  }
82 
83  unsigned int GenerateDescriptionResponse(uint8_t index,
84  uint8_t *data) const;
85 
86  private:
87  PACK(
88  struct description_s {
89  uint8_t setting;
90  char description[MAX_RDM_STRING_LENGTH];
91  });
92 
93  std::string m_description;
94 };
95 
96 
102  public:
107  uint32_t frequency;
108  const char *description;
109  };
110 
112 
117  explicit FrequencyModulationSetting(const ArgType &arg);
118 
123  std::string Description() const { return m_description; }
124 
128  uint32_t Frequency() const { return m_frequency; }
129 
130  unsigned int DescriptionResponseSize() const {
131  return sizeof(description_s);
132  }
133 
134  unsigned int GenerateDescriptionResponse(uint8_t index,
135  uint8_t *data) const;
136 
137  private:
138  PACK(
139  struct description_s {
140  uint8_t setting;
141  uint32_t frequency;
142  char description[MAX_RDM_STRING_LENGTH];
143  });
144 
145  uint32_t m_frequency;
146  std::string m_description;
147 };
148 
149 
158 template <class SettingType>
160  public:
166  SettingCollection(const typename SettingType::ArgType args[],
167  unsigned int arg_count,
168  bool zero_offset = false)
169  : m_zero_offset(zero_offset) {
170  for (unsigned int i = 0; i < arg_count; i++) {
171  m_settings.push_back(SettingType(args[i]));
172  }
173  }
174 
175  uint8_t Count() const { return m_settings.size(); }
176 
177  const SettingType *Lookup(uint8_t index) const {
178  if (index > m_settings.size()) {
179  return NULL;
180  }
181  return &m_settings[index];
182  }
183 
184  unsigned int Offset() const {
185  return m_zero_offset ? 0 : 1;
186  }
187 
188  protected:
189  SettingCollection() {}
190 
191  private:
192  std::vector<SettingType> m_settings;
193  const bool m_zero_offset;
194 };
195 
196 
200 template <class SettingType>
202  public:
203  explicit SettingManager(const SettingCollection<SettingType> *settings)
204  : m_settings(settings),
205  m_current_setting(settings->Offset()) {
206  }
207 
208  virtual ~SettingManager() {}
209 
210  RDMResponse *Get(const RDMRequest *request) const;
211  RDMResponse *Set(const RDMRequest *request);
212  RDMResponse *GetDescription(const RDMRequest *request) const;
213 
214  uint8_t Count() const {
215  return m_settings->Count();
216  }
217 
218  uint8_t CurrentSetting() const {
219  return m_current_setting + m_settings->Offset();
220  }
221 
222  bool ChangeSetting(uint8_t state);
223 
224  private:
225  const SettingCollection<SettingType> *m_settings;
226  uint8_t m_current_setting;
227 };
228 
231 
232 template <class SettingType>
234  uint16_t data = ((m_current_setting + m_settings->Offset()) << 8 |
235  m_settings->Count());
236  if (m_settings->Offset() == 0) {
237  // don't count the 0-state
238  data--;
239  }
240  return ResponderHelper::GetUInt16Value(request, data);
241 }
242 
243 template <class SettingType>
244 RDMResponse *SettingManager<SettingType>::Set(const RDMRequest *request) {
245  uint8_t arg;
246  if (!ResponderHelper::ExtractUInt8(request, &arg)) {
247  return NackWithReason(request, NR_FORMAT_ERROR);
248  }
249 
250  unsigned int offset = m_settings->Offset();
251  if (arg < offset || arg >= m_settings->Count() + offset) {
252  return NackWithReason(request, NR_DATA_OUT_OF_RANGE);
253  } else {
254  m_current_setting = arg - offset;
255  return ResponderHelper::EmptySetResponse(request);
256  }
257 }
258 
259 template <class SettingType>
260 RDMResponse *SettingManager<SettingType>::GetDescription(
261  const RDMRequest *request) const {
262  uint8_t arg;
263  if (!ResponderHelper::ExtractUInt8(request, &arg)) {
264  return NackWithReason(request, NR_FORMAT_ERROR);
265  }
266 
267  unsigned int offset = m_settings->Offset();
268  // never reply for the first setting - see LOCK_STATE
269  if (arg == 0 || arg >= m_settings->Count() + offset) {
270  return NackWithReason(request, NR_DATA_OUT_OF_RANGE);
271  } else {
272  const SettingType *setting = m_settings->Lookup(arg - offset);
273  uint8_t output[
274  setting->DescriptionResponseSize()]; // NOLINT(runtime/arrays)
275  unsigned int size = setting->GenerateDescriptionResponse(arg, output);
276  return GetResponseFromData(request, output, size, RDM_ACK);
277  }
278 }
279 
280 template <class SettingType>
281 bool SettingManager<SettingType>::ChangeSetting(uint8_t new_setting) {
282  uint8_t offset = m_settings->Offset();
283 
284  if (new_setting < offset || new_setting >= m_settings->Count() + offset)
285  return false;
286 
287  m_current_setting = new_setting - offset;
288  return true;
289 }
290 } // namespace rdm
291 } // namespace ola
292 #endif // INCLUDE_OLA_RDM_RESPONDERSETTINGS_H_