Open Lighting Architecture
 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15  *
16  * RDMCommand.h
17  * All the classes that represent RDM commands.
18  * Copyright (C) 2005-2012 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 
133  std::string ToString() const;
134 
135  friend ostream& operator<< (ostream &out, const RDMCommand &command) {
136  return out << command.ToString();
137  }
138 
144  virtual RDMCommandClass CommandClass() const = 0;
145 
152  const UID& SourceUID() const { return m_source; }
153 
155  const UID& DestinationUID() const { return m_destination; }
156 
158  uint8_t TransactionNumber() const { return m_transaction_number; }
159 
161  uint8_t MessageCount() const { return m_message_count; }
162 
164  uint16_t SubDevice() const { return m_sub_device; }
165 
167  uint8_t PortIdResponseType() const { return m_port_id; }
168 
170  uint16_t ParamId() const { return m_param_id; }
171 
173  uint8_t *ParamData() const { return m_data; }
174 
176  unsigned int ParamDataSize() const { return m_data_length; }
177 
187  virtual void Print(CommandPrinter *printer,
188  bool summarize,
189  bool unpack_param_data) const {
190  printer->Print(this, summarize, unpack_param_data);
191  }
192 
197  void Write(ola::io::OutputStream *stream) const;
198 
199  static const uint8_t START_CODE = 0xcc;
200 
201  static RDMCommand *Inflate(const uint8_t *data, unsigned int length);
202 
203  protected:
204  uint8_t m_port_id;
205 
206  RDMCommand(const UID &source,
207  const UID &destination,
208  uint8_t transaction_number,
209  uint8_t port_id,
210  uint8_t message_count,
211  uint16_t sub_device,
212  uint16_t param_id,
213  const uint8_t *data,
214  unsigned int length);
215 
216  void SetParamData(const uint8_t *data, unsigned int length);
217 
218  static rdm_response_code VerifyData(
219  const uint8_t *data,
220  unsigned int length,
221  RDMCommandHeader *command_message);
222 
223  static RDMCommandClass ConvertCommandClass(uint8_t command_type);
224 
225  private:
226  UID m_source;
227  UID m_destination;
228  uint8_t m_transaction_number;
229  uint8_t m_message_count;
230  uint16_t m_sub_device;
231  uint16_t m_param_id;
232  uint8_t *m_data;
233  unsigned int m_data_length;
234 
235  RDMCommand(const RDMCommand &other);
236  bool operator=(const RDMCommand &other) const;
237  RDMCommand& operator=(const RDMCommand &other);
238  static uint16_t CalculateChecksum(const uint8_t *data,
239  unsigned int packet_length);
240 };
241 
242 
246 class RDMRequest: public RDMCommand {
247  public:
248  RDMRequest(const UID &source,
249  const UID &destination,
250  uint8_t transaction_number,
251  uint8_t port_id,
252  uint8_t message_count,
253  uint16_t sub_device,
254  RDMCommandClass command_class,
255  uint16_t param_id,
256  const uint8_t *data,
257  unsigned int length):
258  RDMCommand(source,
259  destination,
260  transaction_number,
261  port_id,
262  message_count,
263  sub_device,
264  param_id,
265  data,
266  length),
267  m_command_class(command_class) {
268  }
269 
270  RDMCommandClass CommandClass() const { return m_command_class; }
271  uint8_t PortId() const { return m_port_id; }
272 
273  virtual RDMRequest *Duplicate() const {
274  return DuplicateWithControllerParams(
275  SourceUID(),
277  PortId());
278  }
279 
280  virtual RDMRequest *DuplicateWithControllerParams(
281  const UID &source,
282  uint8_t transaction_number,
283  uint8_t port_id) const {
284  return new RDMRequest(
285  source,
286  DestinationUID(),
287  transaction_number,
288  port_id,
289  MessageCount(),
290  SubDevice(),
291  m_command_class,
292  ParamId(),
293  ParamData(),
294  ParamDataSize());
295  }
296 
297  virtual void Print(CommandPrinter *printer,
298  bool summarize,
299  bool unpack_param_data) const {
300  printer->Print(this, summarize, unpack_param_data);
301  }
302 
303  // Convert a block of data to an RDMCommand object
304  static RDMRequest* InflateFromData(const uint8_t *data,
305  unsigned int length);
306  static RDMRequest* InflateFromData(const string &data);
307 
308  private:
309  RDMCommandClass m_command_class;
310 };
311 
312 
317  public:
318  RDMGetSetRequest(const UID &source,
319  const UID &destination,
320  uint8_t transaction_number,
321  uint8_t port_id,
322  uint8_t message_count,
323  uint16_t sub_device,
324  RDMCommandClass command_class,
325  uint16_t param_id,
326  const uint8_t *data,
327  unsigned int length):
328  RDMRequest(source,
329  destination,
330  transaction_number,
331  port_id,
332  message_count,
333  sub_device,
334  command_class,
335  param_id,
336  data,
337  length) {
338  }
339 };
340 
341 
342 template <RDMCommand::RDMCommandClass command_class>
344  public:
345  BaseRDMRequest(const UID &source,
346  const UID &destination,
347  uint8_t transaction_number,
348  uint8_t port_id,
349  uint8_t message_count,
350  uint16_t sub_device,
351  uint16_t param_id,
352  const uint8_t *data,
353  unsigned int length):
354  RDMGetSetRequest(source,
355  destination,
356  transaction_number,
357  port_id,
358  message_count,
359  sub_device,
360  command_class,
361  param_id,
362  data,
363  length) {
364  }
365  RDMCommandClass CommandClass() const { return command_class; }
366  BaseRDMRequest<command_class> *Duplicate()
367  const {
368  return DuplicateWithControllerParams(
369  SourceUID(),
371  PortId());
372  }
373 
374  BaseRDMRequest<command_class> *DuplicateWithControllerParams(
375  const UID &source,
376  uint8_t transaction_number,
377  uint8_t port_id) const {
378  return new BaseRDMRequest<command_class>(
379  source,
380  DestinationUID(),
381  transaction_number,
382  port_id,
383  MessageCount(),
384  SubDevice(),
385  ParamId(),
386  ParamData(),
387  ParamDataSize());
388  }
389 };
390 
391 typedef BaseRDMRequest<RDMCommand::GET_COMMAND> RDMGetRequest;
392 typedef BaseRDMRequest<RDMCommand::SET_COMMAND> RDMSetRequest;
393 
394 
399 class RDMResponse: public RDMCommand {
400  public:
401  RDMResponse(const UID &source,
402  const UID &destination,
403  uint8_t transaction_number,
404  uint8_t response_type,
405  uint8_t message_count,
406  uint16_t sub_device,
407  uint16_t param_id,
408  const uint8_t *data,
409  unsigned int length):
410  RDMCommand(source,
411  destination,
412  transaction_number,
413  response_type,
414  message_count,
415  sub_device,
416  param_id,
417  data,
418  length) {
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  // The maximum size of an ACK_OVERFLOW session that we'll buffer
430  // 4k should be big enough for everyone ;)
431  static const unsigned int MAX_OVERFLOW_SIZE = 4 << 10;
432 
433  // Convert a block of data to an RDMResponse object
434  static RDMResponse* InflateFromData(const uint8_t *data,
435  unsigned int length,
436  rdm_response_code *response_code,
437  const RDMRequest *request = NULL);
438  static RDMResponse* InflateFromData(const uint8_t *data,
439  unsigned int length,
440  rdm_response_code *response_code,
441  const RDMRequest *request,
442  uint8_t transaction_number);
443  static RDMResponse* InflateFromData(const string &data,
444  rdm_response_code *response_code,
445  const RDMRequest *request = NULL);
446  static RDMResponse* InflateFromData(const string &data,
447  rdm_response_code *response_code,
448  const RDMRequest *request,
449  uint8_t transaction_number);
450 
451  // Combine two responses into one.
452  static RDMResponse* CombineResponses(const RDMResponse *response1,
453  const RDMResponse *response2);
454 };
455 
456 
461  public:
462  RDMGetSetResponse(const UID &source,
463  const UID &destination,
464  uint8_t transaction_number,
465  uint8_t response_type,
466  uint8_t message_count,
467  uint16_t sub_device,
468  uint16_t param_id,
469  const uint8_t *data,
470  unsigned int length):
471  RDMResponse(source,
472  destination,
473  transaction_number,
474  response_type,
475  message_count,
476  sub_device,
477  param_id,
478  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,
497  destination,
498  transaction_number,
499  response_type,
500  message_count,
501  sub_device,
502  param_id,
503  data,
504  length) {
505  }
506  RDMCommandClass CommandClass() const { return command_class; }
507 };
508 
509 typedef BaseRDMResponse<RDMCommand::GET_COMMAND_RESPONSE> RDMGetResponse;
510 typedef BaseRDMResponse<RDMCommand::SET_COMMAND_RESPONSE> RDMSetResponse;
511 
512 // Helper functions for dealing with RDMCommands
513 // These are mostly used with the RDM-TRI & dummy plugin
515  RDMCommand::RDMCommandClass *command_class,
516  const uint8_t *data,
517  unsigned int length);
518 RDMResponse *NackWithReason(const RDMRequest *request,
519  rdm_nack_reason reason,
520  uint8_t outstanding_messages = 0);
521 RDMResponse *GetResponseFromData(const RDMRequest *request,
522  const uint8_t *data = NULL,
523  unsigned int length = 0,
524  rdm_response_type type = RDM_ACK,
525  uint8_t outstanding_messages = 0);
526 
527 RDMResponse *GetResponseWithPid(const RDMRequest *request,
528  uint16_t pid,
529  const uint8_t *data,
530  unsigned int length,
531  uint8_t type = RDM_ACK,
532  uint8_t outstanding_messages = 0);
533 
538  public:
539  RDMDiscoveryRequest(const UID &source,
540  const UID &destination,
541  uint8_t transaction_number,
542  uint8_t port_id,
543  uint8_t message_count,
544  uint16_t sub_device,
545  uint16_t param_id,
546  const uint8_t *data,
547  unsigned int length)
548  : RDMRequest(source,
549  destination,
550  transaction_number,
551  port_id,
552  message_count,
553  sub_device,
555  param_id,
556  data,
557  length) {
558  }
559 
560  uint8_t PortId() const { return m_port_id; }
561 
562  virtual void Print(CommandPrinter *printer,
563  bool summarize,
564  bool unpack_param_data) const {
565  printer->Print(this, summarize, unpack_param_data);
566  }
567 
568  static RDMDiscoveryRequest* InflateFromData(const uint8_t *data,
569  unsigned int length);
570  static RDMDiscoveryRequest* InflateFromData(const string &data);
571 };
572 
573 
574 // Because the number of discovery requests is small (3 type) we provide a
575 // helper method for each here.
579 RDMDiscoveryRequest *NewDiscoveryUniqueBranchRequest(
580  const UID &source,
581  const UID &lower,
582  const UID &upper,
583  uint8_t transaction_number,
584  uint8_t port_id = 1);
585 
586 
590 RDMDiscoveryRequest *NewMuteRequest(const UID &source,
591  const UID &destination,
592  uint8_t transaction_number,
593  uint8_t port_id = 1);
594 
598 RDMDiscoveryRequest *NewUnMuteRequest(const UID &source,
599  const UID &destination,
600  uint8_t transaction_number,
601  uint8_t port_id = 1);
602 
603 
608  public:
609  RDMDiscoveryResponse(const UID &source,
610  const UID &destination,
611  uint8_t transaction_number,
612  uint8_t port_id,
613  uint8_t message_count,
614  uint16_t sub_device,
615  uint16_t param_id,
616  const uint8_t *data,
617  unsigned int length)
618  : RDMResponse(source,
619  destination,
620  transaction_number,
621  port_id,
622  message_count,
623  sub_device,
624  param_id,
625  data,
626  length) {
627  }
628 
630 
631  virtual void Print(CommandPrinter *printer,
632  bool summarize,
633  bool unpack_param_data) const {
634  printer->Print(this, summarize, unpack_param_data);
635  }
636 
637  static RDMDiscoveryResponse* InflateFromData(const uint8_t *data,
638  unsigned int length);
639  static RDMDiscoveryResponse* InflateFromData(const string &data);
640 };
642 } // namespace rdm
643 } // namespace ola
644 #endif // INCLUDE_OLA_RDM_RDMCOMMAND_H_