Open Lighting Architecture  0.9.6
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ArtNetNode.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
15  *
16  * ArtNetNode.h
17  * Header file for the ArtNetNodeImpl class
18  * Copyright (C) 2005 Simon Newton
19  */
20 
21 #ifndef PLUGINS_ARTNET_ARTNETNODE_H_
22 #define PLUGINS_ARTNET_ARTNETNODE_H_
23 
24 #include <map>
25 #include <memory>
26 #include <string>
27 #include <utility>
28 #include <vector>
29 
30 #include "ola/Callback.h"
31 #include "ola/Clock.h"
32 #include "ola/DmxBuffer.h"
34 #include "ola/network/Interface.h"
35 #include "ola/io/SelectServerInterface.h"
36 #include "ola/network/Socket.h"
38 #include "ola/rdm/RDMCommand.h"
39 #include "ola/rdm/RDMFrame.h"
41 #include "ola/rdm/UIDSet.h"
42 #include "ola/timecode/TimeCode.h"
43 #include "plugins/artnet/ArtNetPackets.h"
44 
45 namespace ola {
46 namespace plugin {
47 namespace artnet {
48 
49 
50 // The directions are the opposite from what OLA uses
51 typedef enum {
52  ARTNET_INPUT_PORT, // sends ArtNet data
53  ARTNET_OUTPUT_PORT, // receives ArtNet data
54 } artnet_port_type;
55 
56 typedef enum {
57  ARTNET_MERGE_HTP, // default
58  ARTNET_MERGE_LTP,
59 } artnet_merge_mode;
60 
61 
62 // This can be passed to SetPortUniverse to disable ports
63 static const uint8_t ARTNET_DISABLE_PORT = 0xf0;
64 
66  public:
68  : always_broadcast(false),
69  use_limited_broadcast_address(false),
70  rdm_queue_size(20),
71  broadcast_threshold(30),
72  input_port_count(4) {
73  }
74 
75  bool always_broadcast;
76  bool use_limited_broadcast_address;
77  unsigned int rdm_queue_size;
78  unsigned int broadcast_threshold;
79  uint8_t input_port_count;
80 };
81 
82 
84  public:
94  const ArtNetNodeOptions &options,
95  ola::network::UDPSocketInterface *socket = NULL);
96 
100  virtual ~ArtNetNodeImpl();
101 
105  bool Start();
106 
110  bool Stop();
111 
128  bool EnterConfigurationMode();
129 
135  bool ExitConfigurationMode();
136 
137 
138  // Various parameters to control the behaviour
143  bool SetShortName(const std::string &name);
144  std::string ShortName() const { return m_short_name; }
145 
150  bool SetLongName(const std::string &name);
151  std::string LongName() const { return m_long_name; }
152 
157  bool SetNetAddress(uint8_t net_address);
158  uint8_t NetAddress() const { return m_net_address; }
159 
164  bool SetSubnetAddress(uint8_t subnet_address);
165  uint8_t SubnetAddress() const {
166  return m_output_ports[0].universe_address >> 4;
167  }
168 
173  uint8_t InputPortCount() const;
174 
178  bool SetInputPortUniverse(uint8_t port_id, uint8_t universe_id);
179 
188  uint8_t GetInputPortUniverse(uint8_t port_id) const;
189 
194  void DisableInputPort(uint8_t port_id);
195 
202  bool InputPortState(uint8_t port_id) const;
203 
209  bool SetOutputPortUniverse(uint8_t port_id, uint8_t universe_id);
210 
216  uint8_t GetOutputPortUniverse(uint8_t port_id);
217 
222  void DisableOutputPort(uint8_t port_id);
223 
230  bool OutputPortState(uint8_t port_id) const;
231 
232  void SetBroadcastThreshold(unsigned int threshold) {
233  m_broadcast_threshold = threshold;
234  }
235 
241  bool SetMergeMode(uint8_t port_id, artnet_merge_mode merge_mode);
242 
248  bool SendPoll();
249 
250  // The following apply to Input Ports (those which send data)
257  bool SendDMX(uint8_t port_id, const ola::DmxBuffer &buffer);
258 
267  void RunFullDiscovery(uint8_t port_id,
269 
279  void RunIncrementalDiscovery(uint8_t port_id,
281 
294  void SendRDMRequest(uint8_t port_id,
295  ola::rdm::RDMRequest *request,
296  ola::rdm::RDMCallback *on_complete);
297 
305  uint8_t port_id,
307 
316  void GetSubscribedNodes(
317  uint8_t port_id,
318  std::vector<ola::network::IPV4Address> *node_addresses);
319 
320  // The following apply to Output Ports (those which receive data);
328  bool SetDMXHandler(uint8_t port_id,
329  DmxBuffer *buffer,
330  ola::Callback0<void> *handler);
331 
337  bool SendTod(uint8_t port_id, const ola::rdm::UIDSet &uid_set);
338 
343  uint8_t port_id,
344  ola::Callback0<void> *on_discover,
345  ola::Callback0<void> *on_flush,
346  ola::Callback2<void,
348  ola::rdm::RDMCallback*> *on_rdm_request);
349 
353  bool SendTimeCode(const ola::timecode::TimeCode &timecode);
354 
355  private:
356  class InputPort;
357  typedef std::vector<InputPort*> InputPorts;
358 
359  // map a uid to a IP address and the number of times we've missed a
360  // response.
361  typedef std::map<ola::rdm::UID,
362  std::pair<ola::network::IPV4Address, uint8_t> > uid_map;
363 
364  enum { MAX_MERGE_SOURCES = 2 };
365 
366  struct DMXSource {
367  DmxBuffer buffer;
368  TimeStamp timestamp;
370  };
371 
372  // Output Ports receive ArtNet data
373  struct OutputPort {
374  uint8_t universe_address;
375  uint8_t sequence_number;
376  bool enabled;
377  artnet_merge_mode merge_mode;
378  bool is_merging;
379  DMXSource sources[MAX_MERGE_SOURCES];
380  DmxBuffer *buffer;
381  std::map<ola::rdm::UID, ola::network::IPV4Address> uid_map;
382  Callback0<void> *on_data;
383  Callback0<void> *on_discover;
384  Callback0<void> *on_flush;
385  ola::Callback2<void,
387  ola::rdm::RDMCallback*> *on_rdm_request;
388  };
389 
390  bool m_running;
391  uint8_t m_net_address; // this is the 'net' portion of the Artnet address
392  bool m_send_reply_on_change;
393  std::string m_short_name;
394  std::string m_long_name;
395  unsigned int m_broadcast_threshold;
396  unsigned int m_unsolicited_replies;
398  bool m_always_broadcast;
399  bool m_use_limited_broadcast_address;
400 
401  // The following keep track of "Configuration mode"
402  bool m_in_configuration_mode;
403  bool m_artpoll_required;
404  bool m_artpollreply_required;
405 
406  InputPorts m_input_ports;
407  OutputPort m_output_ports[ARTNET_MAX_PORTS];
408  ola::network::Interface m_interface;
409  std::auto_ptr<ola::network::UDPSocketInterface> m_socket;
410 
414  void SocketReady();
415 
421  bool SendPollIfAllowed();
422 
430  bool SendPollReplyIfRequired();
431 
435  bool SendPollReply(const ola::network::IPV4Address &destination);
436 
440  bool SendIPReply(const ola::network::IPV4Address &destination);
441 
445  void HandlePacket(const ola::network::IPV4Address &source_address,
446  const artnet_packet &packet,
447  unsigned int packet_size);
448 
452  void HandlePollPacket(const ola::network::IPV4Address &source_address,
453  const artnet_poll_t &packet,
454  unsigned int packet_size);
455 
459  void HandleReplyPacket(const ola::network::IPV4Address &source_address,
460  const artnet_reply_t &packet,
461  unsigned int packet_size);
462 
466  void HandleDataPacket(const ola::network::IPV4Address &source_address,
467  const artnet_dmx_t &packet,
468  unsigned int packet_size);
469 
473  void HandleTodRequest(const ola::network::IPV4Address &source_address,
474  const artnet_todrequest_t &packet,
475  unsigned int packet_size);
476 
480  void HandleTodData(const ola::network::IPV4Address &source_address,
481  const artnet_toddata_t &packet,
482  unsigned int packet_size);
483 
487  void HandleTodControl(const ola::network::IPV4Address &source_address,
488  const artnet_todcontrol_t &packet,
489  unsigned int packet_size);
490 
494  void HandleRdm(const ola::network::IPV4Address &source_address,
495  const artnet_rdm_t &packet,
496  unsigned int packet_size);
497 
501  void RDMRequestCompletion(ola::network::IPV4Address destination,
502  uint8_t port_id,
503  uint8_t universe_address,
504  ola::rdm::RDMReply *reply);
505 
515  void HandleRDMResponse(InputPort *port,
516  const ola::rdm::RDMFrame &rdm_data,
517  const ola::network::IPV4Address &source_address);
518 
522  void HandleIPProgram(const ola::network::IPV4Address &source_address,
523  const artnet_ip_prog_t &packet,
524  unsigned int packet_size);
525 
529  void PopulatePacketHeader(artnet_packet *packet, uint16_t op_code);
530 
537  bool SendPacket(const artnet_packet &packet,
538  unsigned int size,
539  const ola::network::IPV4Address &destination);
540 
545  void TimeoutRDMRequest(InputPort *port);
546 
550  bool SendRDMCommand(const ola::rdm::RDMCommand &command,
551  const ola::network::IPV4Address &destination,
552  uint8_t universe);
553 
557  void UpdatePortFromSource(OutputPort *port, const DMXSource &source);
558 
562  bool CheckPacketVersion(const ola::network::IPV4Address &source_address,
563  const std::string &packet_type,
564  uint16_t version);
565 
569  bool CheckPacketSize(const ola::network::IPV4Address &source_address,
570  const std::string &packet_type,
571  unsigned int actual_size,
572  unsigned int expected_size);
573 
574  // methods for accessing Input & Output ports
578  InputPort *GetInputPort(uint8_t port_id, bool warn = true);
579 
583  const InputPort *GetInputPort(uint8_t port_id) const;
584 
588  InputPort *GetEnabledInputPort(uint8_t port_id, const std::string &action);
589 
593  OutputPort *GetOutputPort(uint8_t port_id);
594 
598  const OutputPort *GetOutputPort(uint8_t port_id) const;
599 
603  OutputPort *GetEnabledOutputPort(uint8_t port_id, const std::string &action);
604 
608  void UpdatePortFromTodPacket(InputPort *port,
609  const ola::network::IPV4Address &source_address,
610  const artnet_toddata_t &packet,
611  unsigned int packet_size);
612 
616  void ReleaseDiscoveryLock(InputPort *port);
617 
624  bool StartDiscoveryProcess(InputPort *port,
626 
630  bool InitNetwork();
631 
632  static const char ARTNET_ID[];
633  static const uint16_t ARTNET_PORT = 6454;
634  static const uint16_t OEM_CODE = 0x0431;
635  static const uint16_t ARTNET_VERSION = 14;
636  // after not receiving a PollReply after this many seconds we declare the
637  // node as dead. This is set to 3x the POLL_INTERVAL in ArtNetDevice.
638  static const uint8_t NODE_CODE = 0x00;
639  static const uint16_t MAX_UIDS_PER_UNIVERSE = 0xffff;
640  static const uint8_t RDM_VERSION = 0x01; // v1.0 standard baby!
641  static const uint8_t TOD_FLUSH_COMMAND = 0x01;
642  static const unsigned int MERGE_TIMEOUT = 10; // As per the spec
643  // seconds after which a node is marked as inactive for the dmx merging
644  static const unsigned int NODE_TIMEOUT = 31;
645  // mseconds we wait for a TodData packet before declaring a node missing
646  static const unsigned int RDM_TOD_TIMEOUT_MS = 4000;
647  // Number of missed TODs before we decide a UID has gone
648  static const unsigned int RDM_MISSED_TODDATA_LIMIT = 3;
649  // The maximum number of requests we'll allow in the queue. This is a per
650  // port (universe) limit.
651  static const unsigned int RDM_REQUEST_QUEUE_LIMIT = 100;
652  // How long to wait for a response to an RDM Request
653  static const unsigned int RDM_REQUEST_TIMEOUT_MS = 2000;
654 
655  DISALLOW_COPY_AND_ASSIGN(ArtNetNodeImpl);
656 };
657 
658 
665  public:
666  ArtNetNodeImplRDMWrapper(ArtNetNodeImpl *impl, uint8_t port_id):
667  m_impl(impl),
668  m_port_id(port_id) {
669  }
671 
673  ola::rdm::RDMCallback *on_complete) {
674  m_impl->SendRDMRequest(m_port_id, request, on_complete);
675  }
676 
678  m_impl->RunFullDiscovery(m_port_id, callback);
679  }
680 
682  m_impl->RunIncrementalDiscovery(m_port_id, callback);
683  }
684 
685  private:
686  ArtNetNodeImpl *m_impl;
687  uint8_t m_port_id;
688 
689  DISALLOW_COPY_AND_ASSIGN(ArtNetNodeImplRDMWrapper);
690 };
691 
692 
696 class ArtNetNode {
697  public:
698  ArtNetNode(const ola::network::Interface &iface,
700  const ArtNetNodeOptions &options,
701  ola::network::UDPSocketInterface *socket = NULL);
702  virtual ~ArtNetNode();
703 
704  bool Start() { return m_impl.Start(); }
705  bool Stop() { return m_impl.Stop(); }
706 
707  bool EnterConfigurationMode() {
708  return m_impl.EnterConfigurationMode();
709  }
710  bool ExitConfigurationMode() {
711  return m_impl.ExitConfigurationMode();
712  }
713 
714  // Various parameters to control the behaviour
715  bool SetShortName(const std::string &name) {
716  return m_impl.SetShortName(name);
717  }
718 
719  std::string ShortName() const { return m_impl.ShortName(); }
720  bool SetLongName(const std::string &name) {
721  return m_impl.SetLongName(name);
722  }
723 
724  std::string LongName() const { return m_impl.LongName(); }
725 
726  uint8_t NetAddress() const { return m_impl.NetAddress(); }
727  bool SetNetAddress(uint8_t net_address) {
728  return m_impl.SetNetAddress(net_address);
729  }
730  bool SetSubnetAddress(uint8_t subnet_address) {
731  return m_impl.SetSubnetAddress(subnet_address);
732  }
733  uint8_t SubnetAddress() const {
734  return m_impl.SubnetAddress();
735  }
736 
737  uint8_t InputPortCount() const {
738  return m_impl.InputPortCount();
739  }
740 
741  bool SetInputPortUniverse(uint8_t port_id, uint8_t universe_id) {
742  return m_impl.SetInputPortUniverse(port_id, universe_id);
743  }
744  uint8_t GetInputPortUniverse(uint8_t port_id) const {
745  return m_impl.GetInputPortUniverse(port_id);
746  }
747  void DisableInputPort(uint8_t port_id) {
748  m_impl.DisableInputPort(port_id);
749  }
750  bool InputPortState(uint8_t port_id) const {
751  return m_impl.InputPortState(port_id);
752  }
753 
754  bool SetOutputPortUniverse(uint8_t port_id, uint8_t universe_id) {
755  return m_impl.SetOutputPortUniverse(port_id, universe_id);
756  }
757  uint8_t GetOutputPortUniverse(uint8_t port_id) {
758  return m_impl.GetOutputPortUniverse(port_id);
759  }
760  void DisableOutputPort(uint8_t port_id) {
761  m_impl.DisableOutputPort(port_id);
762  }
763  bool OutputPortState(uint8_t port_id) const {
764  return m_impl.OutputPortState(port_id);
765  }
766 
767  void SetBroadcastThreshold(unsigned int threshold) {
768  m_impl.SetBroadcastThreshold(threshold);
769  }
770 
771  bool SetMergeMode(uint8_t port_id, artnet_merge_mode merge_mode) {
772  return m_impl.SetMergeMode(port_id, merge_mode);
773  }
774 
775  // Poll, this should be called periodically if we're sending data.
776  bool SendPoll() {
777  return m_impl.SendPoll();
778  }
779 
780  // The following apply to Input Ports (those which send data)
781  bool SendDMX(uint8_t port_id, const ola::DmxBuffer &buffer) {
782  return m_impl.SendDMX(port_id, buffer);
783  }
784 
788  void RunFullDiscovery(uint8_t port_id,
790 
794  void RunIncrementalDiscovery(uint8_t port_id,
796 
800  void SendRDMRequest(uint8_t port_id,
801  ola::rdm::RDMRequest *request,
802  ola::rdm::RDMCallback *on_complete);
803 
804  /*
805  * @brief This handler is called if we receive ArtTod packets and a discovery
806  * process isn't running.
807  */
808  bool SetUnsolicitedUIDSetHandler(
809  uint8_t port_id,
811  return m_impl.SetUnsolicitedUIDSetHandler(port_id, on_tod);
812  }
813  void GetSubscribedNodes(
814  uint8_t port_id,
815  std::vector<ola::network::IPV4Address> *node_addresses) {
816  m_impl.GetSubscribedNodes(port_id, node_addresses);
817  }
818 
819  // The following apply to Output Ports (those which receive data);
820  bool SetDMXHandler(uint8_t port_id,
821  DmxBuffer *buffer,
822  ola::Callback0<void> *handler) {
823  return m_impl.SetDMXHandler(port_id, buffer, handler);
824  }
825  bool SendTod(uint8_t port_id, const ola::rdm::UIDSet &uid_set) {
826  return m_impl.SendTod(port_id, uid_set);
827  }
828  bool SetOutputPortRDMHandlers(
829  uint8_t port_id,
830  ola::Callback0<void> *on_discover,
831  ola::Callback0<void> *on_flush,
832  ola::Callback2<void,
834  ola::rdm::RDMCallback*> *on_rdm_request) {
835  return m_impl.SetOutputPortRDMHandlers(port_id,
836  on_discover,
837  on_flush,
838  on_rdm_request);
839  }
840 
841  // Time Code methods
842  bool SendTimeCode(const ola::timecode::TimeCode &timecode) {
843  return m_impl.SendTimeCode(timecode);
844  }
845 
846  private:
847  ArtNetNodeImpl m_impl;
848  std::vector<ArtNetNodeImplRDMWrapper*> m_wrappers;
849  std::vector<ola::rdm::DiscoverableQueueingRDMController*> m_controllers;
850 
855  bool CheckInputPortId(uint8_t port_id);
856 
857  DISALLOW_COPY_AND_ASSIGN(ArtNetNode);
858 };
859 } // namespace artnet
860 } // namespace plugin
861 } // namespace ola
862 #endif // PLUGINS_ARTNET_ARTNETNODE_H_