Open Lighting Architecture  0.9.0
 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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/rdm/RDMCommand.h>
25 #include <stdint.h>
26 #include <string>
27 #include <vector>
28 
29 namespace ola {
30 namespace rdm {
31 
36  public:
37  virtual ~SettingInterface() {}
38 
43  virtual std::string Description() const = 0;
44 
48  virtual unsigned int DescriptionResponseSize() const = 0;
49 
55  virtual unsigned int GenerateDescriptionResponse(uint8_t index,
56  uint8_t *data) const = 0;
57 };
58 
63  public:
64  typedef const char* ArgType;
65 
70  explicit BasicSetting(const ArgType description);
71 
76  std::string Description() const { return m_description; }
77 
78  unsigned int DescriptionResponseSize() const {
79  return sizeof(description_s);
80  }
81 
82  unsigned int GenerateDescriptionResponse(uint8_t index,
83  uint8_t *data) const;
84 
85  private:
86  struct description_s {
87  uint8_t setting;
88  char description[MAX_RDM_STRING_LENGTH];
89  } __attribute__((packed));
90 
91  std::string m_description;
92 };
93 
94 
100  public:
105  uint32_t frequency;
106  const char *description;
107  };
108 
110 
115  explicit FrequencyModulationSetting(const ArgType &arg);
116 
121  std::string Description() const { return m_description; }
122 
126  uint32_t Frequency() const { return m_frequency; }
127 
128  unsigned int DescriptionResponseSize() const {
129  return sizeof(description_s);
130  }
131 
132  unsigned int GenerateDescriptionResponse(uint8_t index,
133  uint8_t *data) const;
134 
135  private:
136  struct description_s {
137  uint8_t setting;
138  uint32_t frequency;
139  char description[MAX_RDM_STRING_LENGTH];
140  } __attribute__((packed));
141 
142  uint32_t m_frequency;
143  std::string m_description;
144 };
145 
146 
155 template <class SettingType>
157  public:
163  SettingCollection(const typename SettingType::ArgType args[],
164  unsigned int arg_count,
165  bool zero_offset = false)
166  : m_zero_offset(zero_offset) {
167  for (unsigned int i = 0; i < arg_count; i++) {
168  m_settings.push_back(SettingType(args[i]));
169  }
170  }
171 
172  uint8_t Count() const { return m_settings.size(); }
173 
174  const SettingType *Lookup(uint8_t index) const {
175  if (index > m_settings.size()) {
176  return NULL;
177  }
178  return &m_settings[index];
179  }
180 
181  unsigned int Offset() const {
182  return m_zero_offset ? 0 : 1;
183  }
184 
185  protected:
186  SettingCollection() {}
187 
188  private:
189  std::vector<SettingType> m_settings;
190  const bool m_zero_offset;
191 };
192 
193 
197 template <class SettingType>
199  public:
200  explicit SettingManager(const SettingCollection<SettingType> *settings)
201  : m_settings(settings),
202  m_current_setting(settings->Offset()) {
203  }
204 
205  virtual ~SettingManager() {}
206 
207  const RDMResponse *Get(const RDMRequest *request) const;
208  const RDMResponse *Set(const RDMRequest *request);
209  const RDMResponse *GetDescription(const RDMRequest *request) const;
210 
211  uint8_t Count() const {
212  return m_settings->Count();
213  }
214 
215  uint8_t CurrentSetting() const {
216  return m_current_setting + m_settings->Offset();
217  }
218 
219  bool ChangeSetting(uint8_t state);
220 
221  private:
222  const SettingCollection<SettingType> *m_settings;
223  uint8_t m_current_setting;
224 };
225 
228 
229 template <class SettingType>
231  const RDMRequest *request) const {
232  uint16_t data = ((m_current_setting + m_settings->Offset()) << 8 |
233  m_settings->Count());
234  if (m_settings->Offset() == 0) {
235  // don't count the 0-state
236  data--;
237  }
238  return ResponderHelper::GetUInt16Value(request, data);
239 }
240 
241 template <class SettingType>
242 const RDMResponse *SettingManager<SettingType>::Set(
243  const RDMRequest *request) {
244  uint8_t arg;
245  if (!ResponderHelper::ExtractUInt8(request, &arg)) {
246  return NackWithReason(request, NR_FORMAT_ERROR);
247  }
248 
249  unsigned int offset = m_settings->Offset();
250  if (arg < offset || arg >= m_settings->Count() + offset) {
251  return NackWithReason(request, NR_DATA_OUT_OF_RANGE);
252  } else {
253  m_current_setting = arg - offset;
254  return ResponderHelper::EmptySetResponse(request);
255  }
256 }
257 
258 template <class SettingType>
259 const RDMResponse *SettingManager<SettingType>::GetDescription(
260  const RDMRequest *request) const {
261  uint8_t arg;
262  if (!ResponderHelper::ExtractUInt8(request, &arg)) {
263  return NackWithReason(request, NR_FORMAT_ERROR);
264  }
265 
266  unsigned int offset = m_settings->Offset();
267  // never reply for the first setting - see LOCK_STATE
268  if (arg == 0 || arg >= m_settings->Count() + offset) {
269  return NackWithReason(request, NR_DATA_OUT_OF_RANGE);
270  } else {
271  const SettingType *setting = m_settings->Lookup(arg - offset);
272  uint8_t output[setting->DescriptionResponseSize()]; // NOLINT
273  unsigned int size = setting->GenerateDescriptionResponse(arg, output);
274  return GetResponseFromData(request, output, size, RDM_ACK);
275  }
276 }
277 
278 template <class SettingType>
279 bool SettingManager<SettingType>::ChangeSetting(uint8_t new_setting) {
280  uint8_t offset = m_settings->Offset();
281 
282  if (new_setting < offset || new_setting >= m_settings->Count() + offset)
283  return false;
284 
285  m_current_setting = new_setting - offset;
286  return true;
287 }
288 } // namespace rdm
289 } // namespace ola
290 #endif // INCLUDE_OLA_RDM_RESPONDERSETTINGS_H_