Open Lighting Architecture  0.9.2
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
RDMCommand.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  * RDMCommand.h
17  * All the classes that represent RDM commands.
18  * Copyright (C) 2005 Simon Newton
19  */
20 
21 
30 #ifndef INCLUDE_OLA_RDM_RDMCOMMAND_H_
31 #define INCLUDE_OLA_RDM_RDMCOMMAND_H_
32 
33 #include <stdint.h>
34 #include <ola/io/OutputStream.h>
35 #include <ola/rdm/CommandPrinter.h>
36 #include <ola/rdm/RDMEnums.h>
37 #include <ola/rdm/RDMPacket.h>
38 #include <ola/rdm/RDMResponseCodes.h>
39 #include <ola/rdm/UID.h>
40 #include <sstream>
41 #include <string>
42 
43 namespace ola {
44 namespace rdm {
45 
55 typedef enum {
60 
61 
68 /*
69  *
70  * TODO: make these reference counted so that fan out during broadcasts isn't
71  * as expensive.
72  */
73 class RDMCommand {
74  public:
79  typedef enum {
82  GET_COMMAND = 0x20,
84  SET_COMMAND = 0x30,
86  INVALID_COMMAND = 0xff,
88 
89  virtual ~RDMCommand();
90 
95  bool operator==(const RDMCommand &other) const;
96 
106  switch (CommandClass()) {
107  case DISCOVER_COMMAND:
108  case GET_COMMAND:
109  case SET_COMMAND:
110  return RDM_REQUEST;
114  return RDM_RESPONSE;
115  default:
116  return RDM_INVALID;
117  }
118  }
119 
131  std::string ToString() const;
132 
139  friend std::ostream& operator<< (std::ostream &out,
140  const RDMCommand &command) {
141  return out << command.ToString();
142  }
143 
149  virtual RDMCommandClass CommandClass() const = 0;
150 
157  const UID& SourceUID() const { return m_source; }
158 
160  const UID& DestinationUID() const { return m_destination; }
161 
163  uint8_t TransactionNumber() const { return m_transaction_number; }
164 
166  uint8_t MessageCount() const { return m_message_count; }
167 
169  uint16_t SubDevice() const { return m_sub_device; }
170 
172  uint8_t PortIdResponseType() const { return m_port_id; }
173 
175  uint16_t ParamId() const { return m_param_id; }
176 
178  uint8_t *ParamData() const { return m_data; }
179 
181  unsigned int ParamDataSize() const { return m_data_length; }
182 
192  virtual void Print(CommandPrinter *printer,
193  bool summarize,
194  bool unpack_param_data) const {
195  printer->Print(this, summarize, unpack_param_data);
196  }
197 
202  void Write(ola::io::OutputStream *stream) const;
203 
204  static const uint8_t START_CODE = 0xcc;
205 
206  static RDMCommand *Inflate(const uint8_t *data, unsigned int length);
207 
208  protected:
209  uint8_t m_port_id;
210 
211  RDMCommand(const UID &source,
212  const UID &destination,
213  uint8_t transaction_number,
214  uint8_t port_id,
215  uint8_t message_count,
216  uint16_t sub_device,
217  uint16_t param_id,
218  const uint8_t *data,
219  unsigned int length);
220 
221  void SetParamData(const uint8_t *data, unsigned int length);
222 
223  static rdm_response_code VerifyData(
224  const uint8_t *data,
225  unsigned int length,
226  RDMCommandHeader *command_message);
227 
228  static RDMCommandClass ConvertCommandClass(uint8_t command_type);
229 
230  private:
231  UID m_source;
232  UID m_destination;
233  uint8_t m_transaction_number;
234  uint8_t m_message_count;
235  uint16_t m_sub_device;
236  uint16_t m_param_id;
237  uint8_t *m_data;
238  unsigned int m_data_length;
239 
240  RDMCommand(const RDMCommand &other);
241  bool operator=(const RDMCommand &other) const;
242  RDMCommand& operator=(const RDMCommand &other);
243  static uint16_t CalculateChecksum(const uint8_t *data,
244  unsigned int packet_length);
245 };
246 
247 
251 class RDMRequest: public RDMCommand {
252  public:
253  RDMRequest(const UID &source,
254  const UID &destination,
255  uint8_t transaction_number,
256  uint8_t port_id,
257  uint8_t message_count,
258  uint16_t sub_device,
259  RDMCommandClass command_class,
260  uint16_t param_id,
261  const uint8_t *data,
262  unsigned int length):
263  RDMCommand(source,
264  destination,
265  transaction_number,
266  port_id,
267  message_count,
268  sub_device,
269  param_id,
270  data,
271  length),
272  m_command_class(command_class) {
273  }
274 
275  RDMCommandClass CommandClass() const { return m_command_class; }
276  uint8_t PortId() const { return m_port_id; }
277 
278  virtual RDMRequest *Duplicate() const {
279  return DuplicateWithControllerParams(
280  SourceUID(),
282  PortId());
283  }
284 
285  virtual RDMRequest *DuplicateWithControllerParams(
286  const UID &source,
287  uint8_t transaction_number,
288  uint8_t port_id) const {
289  return new RDMRequest(
290  source,
291  DestinationUID(),
292  transaction_number,
293  port_id,
294  MessageCount(),
295  SubDevice(),
296  m_command_class,
297  ParamId(),
298  ParamData(),
299  ParamDataSize());
300  }
301 
302  virtual void Print(CommandPrinter *printer,
303  bool summarize,
304  bool unpack_param_data) const {
305  printer->Print(this, summarize, unpack_param_data);
306  }
307 
308  // Convert a block of data to an RDMCommand object
309  static RDMRequest* InflateFromData(const uint8_t *data,
310  unsigned int length);
311  static RDMRequest* InflateFromData(const std::string &data);
312 
313  private:
314  RDMCommandClass m_command_class;
315 };
316 
317 
322  public:
323  RDMGetSetRequest(const UID &source,
324  const UID &destination,
325  uint8_t transaction_number,
326  uint8_t port_id,
327  uint8_t message_count,
328  uint16_t sub_device,
329  RDMCommandClass command_class,
330  uint16_t param_id,
331  const uint8_t *data,
332  unsigned int length):
333  RDMRequest(source,
334  destination,
335  transaction_number,
336  port_id,
337  message_count,
338  sub_device,
339  command_class,
340  param_id,
341  data,
342  length) {
343  }
344 };
345 
346 
347 template <RDMCommand::RDMCommandClass command_class>
349  public:
350  BaseRDMRequest(const UID &source,
351  const UID &destination,
352  uint8_t transaction_number,
353  uint8_t port_id,
354  uint8_t message_count,
355  uint16_t sub_device,
356  uint16_t param_id,
357  const uint8_t *data,
358  unsigned int length):
359  RDMGetSetRequest(source,
360  destination,
361  transaction_number,
362  port_id,
363  message_count,
364  sub_device,
365  command_class,
366  param_id,
367  data,
368  length) {
369  }
370  RDMCommandClass CommandClass() const { return command_class; }
371  BaseRDMRequest<command_class> *Duplicate()
372  const {
373  return DuplicateWithControllerParams(
374  SourceUID(),
376  PortId());
377  }
378 
379  BaseRDMRequest<command_class> *DuplicateWithControllerParams(
380  const UID &source,
381  uint8_t transaction_number,
382  uint8_t port_id) const {
383  return new BaseRDMRequest<command_class>(
384  source,
385  DestinationUID(),
386  transaction_number,
387  port_id,
388  MessageCount(),
389  SubDevice(),
390  ParamId(),
391  ParamData(),
392  ParamDataSize());
393  }
394 };
395 
396 typedef BaseRDMRequest<RDMCommand::GET_COMMAND> RDMGetRequest;
397 typedef BaseRDMRequest<RDMCommand::SET_COMMAND> RDMSetRequest;
398 
399 
404 class RDMResponse: public RDMCommand {
405  public:
406  RDMResponse(const UID &source,
407  const UID &destination,
408  uint8_t transaction_number,
409  uint8_t response_type,
410  uint8_t message_count,
411  uint16_t sub_device,
412  RDMCommand::RDMCommandClass command_class,
413  uint16_t param_id,
414  const uint8_t *data,
415  unsigned int length)
416  : RDMCommand(source, destination, transaction_number, response_type,
417  message_count, sub_device, param_id, data, length),
418  m_command_class(command_class) {
419  }
420 
421  uint8_t ResponseType() const { return m_port_id; }
422 
423  virtual void Print(CommandPrinter *printer,
424  bool summarize,
425  bool unpack_param_data) const {
426  printer->Print(this, summarize, unpack_param_data);
427  }
428 
429  RDMCommandClass CommandClass() const { return m_command_class; }
430 
431  // The maximum size of an ACK_OVERFLOW session that we'll buffer
432  // 4k should be big enough for everyone ;)
433  static const unsigned int MAX_OVERFLOW_SIZE = 4 << 10;
434 
435  // Convert a block of data to an RDMResponse object
436  static RDMResponse* InflateFromData(const uint8_t *data,
437  unsigned int length,
438  rdm_response_code *response_code,
439  const RDMRequest *request = NULL);
440  static RDMResponse* InflateFromData(const uint8_t *data,
441  unsigned int length,
442  rdm_response_code *response_code,
443  const RDMRequest *request,
444  uint8_t transaction_number);
445  static RDMResponse* InflateFromData(const std::string &data,
446  rdm_response_code *response_code,
447  const RDMRequest *request = NULL);
448  static RDMResponse* InflateFromData(const std::string &data,
449  rdm_response_code *response_code,
450  const RDMRequest *request,
451  uint8_t transaction_number);
452 
453  // Combine two responses into one.
454  static RDMResponse* CombineResponses(const RDMResponse *response1,
455  const RDMResponse *response2);
456 
457  private:
458  RDMCommand::RDMCommandClass m_command_class;
459 };
460 
461 
466  public:
467  RDMGetSetResponse(const UID &source,
468  const UID &destination,
469  uint8_t transaction_number,
470  uint8_t response_type,
471  uint8_t message_count,
472  uint16_t sub_device,
473  RDMCommand::RDMCommandClass command_class,
474  uint16_t param_id,
475  const uint8_t *data,
476  unsigned int length)
477  : RDMResponse(source, destination, transaction_number, response_type,
478  message_count, sub_device, command_class, param_id, data,
479  length) {
480  }
481 };
482 
483 
484 template <RDMCommand::RDMCommandClass command_class>
486  public:
487  BaseRDMResponse(const UID &source,
488  const UID &destination,
489  uint8_t transaction_number,
490  uint8_t response_type,
491  uint8_t message_count,
492  uint16_t sub_device,
493  uint16_t param_id,
494  const uint8_t *data,
495  unsigned int length)
496  : RDMGetSetResponse(source, destination, transaction_number,
497  response_type, message_count, sub_device,
498  command_class, param_id, data, length) {
499  }
500 };
501 
504 
505 // Helper functions for dealing with RDMCommands
506 // These are mostly used with the RDM-TRI & dummy plugin
508  RDMCommand::RDMCommandClass *command_class,
509  const uint8_t *data,
510  unsigned int length);
511 RDMResponse *NackWithReason(const RDMRequest *request,
512  rdm_nack_reason reason,
513  uint8_t outstanding_messages = 0);
514 RDMResponse *GetResponseFromData(const RDMRequest *request,
515  const uint8_t *data = NULL,
516  unsigned int length = 0,
517  rdm_response_type type = RDM_ACK,
518  uint8_t outstanding_messages = 0);
519 
521  uint16_t pid,
522  const uint8_t *data,
523  unsigned int length,
524  uint8_t type = RDM_ACK,
525  uint8_t outstanding_messages = 0);
526 
531  public:
532  RDMDiscoveryRequest(const UID &source,
533  const UID &destination,
534  uint8_t transaction_number,
535  uint8_t port_id,
536  uint8_t message_count,
537  uint16_t sub_device,
538  uint16_t param_id,
539  const uint8_t *data,
540  unsigned int length)
541  : RDMRequest(source,
542  destination,
543  transaction_number,
544  port_id,
545  message_count,
546  sub_device,
548  param_id,
549  data,
550  length) {
551  }
552 
553  uint8_t PortId() const { return m_port_id; }
554 
555  virtual void Print(CommandPrinter *printer,
556  bool summarize,
557  bool unpack_param_data) const {
558  printer->Print(this, summarize, unpack_param_data);
559  }
560 
561  static RDMDiscoveryRequest* InflateFromData(const uint8_t *data,
562  unsigned int length);
563  static RDMDiscoveryRequest* InflateFromData(const std::string &data);
564 };
565 
566 
567 // Because the number of discovery requests is small (3 type) we provide a
568 // helper method for each here.
572 RDMDiscoveryRequest *NewDiscoveryUniqueBranchRequest(
573  const UID &source,
574  const UID &lower,
575  const UID &upper,
576  uint8_t transaction_number,
577  uint8_t port_id = 1);
578 
579 
583 RDMDiscoveryRequest *NewMuteRequest(const UID &source,
584  const UID &destination,
585  uint8_t transaction_number,
586  uint8_t port_id = 1);
587 
591 RDMDiscoveryRequest *NewUnMuteRequest(const UID &source,
592  const UID &destination,
593  uint8_t transaction_number,
594  uint8_t port_id = 1);
595 
596 
601  public:
602  RDMDiscoveryResponse(const UID &source,
603  const UID &destination,
604  uint8_t transaction_number,
605  uint8_t port_id,
606  uint8_t message_count,
607  uint16_t sub_device,
608  uint16_t param_id,
609  const uint8_t *data,
610  unsigned int length)
611  : RDMResponse(source,
612  destination,
613  transaction_number,
614  port_id,
615  message_count,
616  sub_device,
618  param_id,
619  data,
620  length) {
621  }
622 
623  virtual void Print(CommandPrinter *printer,
624  bool summarize,
625  bool unpack_param_data) const {
626  printer->Print(this, summarize, unpack_param_data);
627  }
628 
629  static RDMDiscoveryResponse* InflateFromData(const uint8_t *data,
630  unsigned int length);
631  static RDMDiscoveryResponse* InflateFromData(const std::string &data);
632 };
634 } // namespace rdm
635 } // namespace ola
636 #endif // INCLUDE_OLA_RDM_RDMCOMMAND_H_