Open Lighting Architecture
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ResponderSettings.h
1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or
5  * (at your option) any later version.
6  *
7  * This program 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
10  * GNU Library General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; 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 
32 using std::string;
33 
38  public:
39  virtual ~SettingInterface() {}
40 
45  virtual string Description() const = 0;
46 
50  virtual unsigned int DescriptionResponseSize() const = 0;
51 
57  virtual unsigned int GenerateDescriptionResponse(uint8_t index,
58  uint8_t *data) const = 0;
59 };
60 
65  public:
66  typedef const char* ArgType;
67 
72  explicit BasicSetting(const ArgType description);
73 
78  string Description() const { return m_description; }
79 
80  unsigned int DescriptionResponseSize() const {
81  return sizeof(description_s);
82  }
83 
84  unsigned int GenerateDescriptionResponse(uint8_t index,
85  uint8_t *data) const;
86 
87  private:
88  struct description_s {
89  uint8_t setting;
90  char description[MAX_RDM_STRING_LENGTH];
91  } __attribute__((packed));
92 
93  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  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  struct description_s {
139  uint8_t setting;
140  uint32_t frequency;
141  char description[MAX_RDM_STRING_LENGTH];
142  } __attribute__((packed));
143 
144  uint32_t m_frequency;
145  string m_description;
146 };
147 
148 
157 template <class SettingType>
159  public:
165  SettingCollection(const typename SettingType::ArgType args[],
166  unsigned int arg_count,
167  bool zero_offset = false)
168  : m_zero_offset(zero_offset) {
169  for (unsigned int i = 0; i < arg_count; i++) {
170  m_settings.push_back(SettingType(args[i]));
171  }
172  }
173 
174  uint8_t Count() const { return m_settings.size(); }
175 
176  const SettingType *Lookup(uint8_t index) const {
177  if (index > m_settings.size()) {
178  return NULL;
179  }
180  return &m_settings[index];
181  }
182 
183  unsigned int Offset() const {
184  return m_zero_offset ? 0 : 1;
185  }
186 
187  protected:
188  SettingCollection() {}
189 
190  private:
191  std::vector<SettingType> m_settings;
192  const bool m_zero_offset;
193 };
194 
195 
199 template <class SettingType>
201  public:
202  explicit SettingManager(const SettingCollection<SettingType> *settings)
203  : m_settings(settings),
204  m_current_setting(settings->Offset()) {
205  }
206 
207  virtual ~SettingManager() {}
208 
209  const RDMResponse *Get(const RDMRequest *request) const;
210  const RDMResponse *Set(const RDMRequest *request);
211  const RDMResponse *GetDescription(const RDMRequest *request) const;
212 
213  uint8_t Count() const {
214  return m_settings->Count();
215  }
216 
217  uint8_t CurrentSetting() const {
218  return m_current_setting + m_settings->Offset();
219  }
220 
221  bool ChangeSetting(uint8_t state);
222 
223  private:
224  const SettingCollection<SettingType> *m_settings;
225  uint8_t m_current_setting;
226 };
227 
230 
231 template <class SettingType>
233  const RDMRequest *request) const {
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 const RDMResponse *SettingManager<SettingType>::Set(
245  const RDMRequest *request) {
246  uint8_t arg;
247  if (!ResponderHelper::ExtractUInt8(request, &arg)) {
248  return NackWithReason(request, NR_FORMAT_ERROR);
249  }
250 
251  unsigned int offset = m_settings->Offset();
252  if (arg < offset || arg >= m_settings->Count() + offset) {
253  return NackWithReason(request, NR_DATA_OUT_OF_RANGE);
254  } else {
255  m_current_setting = arg - offset;
256  return ResponderHelper::EmptySetResponse(request);
257  }
258 }
259 
260 template <class SettingType>
261 const RDMResponse *SettingManager<SettingType>::GetDescription(
262  const RDMRequest *request) const {
263  uint8_t arg;
264  if (!ResponderHelper::ExtractUInt8(request, &arg)) {
265  return NackWithReason(request, NR_FORMAT_ERROR);
266  }
267 
268  unsigned int offset = m_settings->Offset();
269  // never reply for the first setting - see LOCK_STATE
270  if (arg == 0 || arg >= m_settings->Count() + offset) {
271  return NackWithReason(request, NR_DATA_OUT_OF_RANGE);
272  } else {
273  const SettingType *setting = m_settings->Lookup(arg - offset);
274  uint8_t output[setting->DescriptionResponseSize()]; // NOLINT
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_