Open Lighting Architecture  Latest Git
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 Art-Net data
53  ARTNET_OUTPUT_PORT, // receives Art-Net 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 
304  bool SetUnsolicitedUIDSetHandler(
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 
342  bool SetOutputPortRDMHandlers(
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 Art-Net 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 Art-Net 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 
516  void HandleRDMResponse(InputPort *port,
517  const ola::rdm::RDMFrame &rdm_data,
518  const ola::network::IPV4Address &source_address);
519 
523  void HandleIPProgram(const ola::network::IPV4Address &source_address,
524  const artnet_ip_prog_t &packet,
525  unsigned int packet_size);
526 
530  void PopulatePacketHeader(artnet_packet *packet, uint16_t op_code);
531 
538  bool SendPacket(const artnet_packet &packet,
539  unsigned int size,
540  const ola::network::IPV4Address &destination);
541 
546  void TimeoutRDMRequest(InputPort *port);
547 
551  bool SendRDMCommand(const ola::rdm::RDMCommand &command,
552  const ola::network::IPV4Address &destination,
553  uint8_t universe);
554 
558  void UpdatePortFromSource(OutputPort *port, const DMXSource &source);
559 
563  bool CheckPacketVersion(const ola::network::IPV4Address &source_address,
564  const std::string &packet_type,
565  uint16_t version);
566 
570  bool CheckPacketSize(const ola::network::IPV4Address &source_address,
571  const std::string &packet_type,
572  unsigned int actual_size,
573  unsigned int expected_size);
574 
575  // methods for accessing Input & Output ports
579  InputPort *GetInputPort(uint8_t port_id, bool warn = true);
580 
584  const InputPort *GetInputPort(uint8_t port_id) const;
585 
589  InputPort *GetEnabledInputPort(uint8_t port_id, const std::string &action);
590 
594  OutputPort *GetOutputPort(uint8_t port_id);
595 
599  const OutputPort *GetOutputPort(uint8_t port_id) const;
600 
604  OutputPort *GetEnabledOutputPort(uint8_t port_id, const std::string &action);
605 
609  void UpdatePortFromTodPacket(InputPort *port,
610  const ola::network::IPV4Address &source_address,
611  const artnet_toddata_t &packet,
612  unsigned int packet_size);
613 
617  void ReleaseDiscoveryLock(InputPort *port);
618 
625  bool StartDiscoveryProcess(InputPort *port,
627 
631  bool InitNetwork();
632 
633  static const char ARTNET_ID[];
634  static const uint16_t ARTNET_PORT = 6454;
635  static const uint16_t OEM_CODE = 0x0431;
636  static const uint16_t ARTNET_VERSION = 14;
637  // after not receiving a PollReply after this many seconds we declare the
638  // node as dead. This is set to 3x the POLL_INTERVAL in ArtNetDevice.
639  static const uint8_t NODE_CODE = 0x00;
640  static const uint16_t MAX_UIDS_PER_UNIVERSE = 0xffff;
641  static const uint8_t RDM_VERSION = 0x01; // v1.0 standard baby!
642  static const uint8_t TOD_FLUSH_COMMAND = 0x01;
643  static const unsigned int MERGE_TIMEOUT = 10; // As per the spec
644  // seconds after which a node is marked as inactive for the dmx merging
645  static const unsigned int NODE_TIMEOUT = 31;
646  // mseconds we wait for a TodData packet before declaring a node missing
647  static const unsigned int RDM_TOD_TIMEOUT_MS = 4000;
648  // Number of missed TODs before we decide a UID has gone
649  static const unsigned int RDM_MISSED_TODDATA_LIMIT = 3;
650  // The maximum number of requests we'll allow in the queue. This is a per
651  // port (universe) limit.
652  static const unsigned int RDM_REQUEST_QUEUE_LIMIT = 100;
653  // How long to wait for a response to an RDM Request
654  static const unsigned int RDM_REQUEST_TIMEOUT_MS = 2000;
655 
657 };
658 
659 
666  public:
667  ArtNetNodeImplRDMWrapper(ArtNetNodeImpl *impl, uint8_t port_id):
668  m_impl(impl),
669  m_port_id(port_id) {
670  }
672 
674  ola::rdm::RDMCallback *on_complete) {
675  m_impl->SendRDMRequest(m_port_id, request, on_complete);
676  }
677 
679  m_impl->RunFullDiscovery(m_port_id, callback);
680  }
681 
683  m_impl->RunIncrementalDiscovery(m_port_id, callback);
684  }
685 
686  private:
687  ArtNetNodeImpl *m_impl;
688  uint8_t m_port_id;
689 
691 };
692 
693 
697 class ArtNetNode {
698  public:
699  ArtNetNode(const ola::network::Interface &iface,
701  const ArtNetNodeOptions &options,
702  ola::network::UDPSocketInterface *socket = NULL);
703  virtual ~ArtNetNode();
704 
705  bool Start() { return m_impl.Start(); }
706  bool Stop() { return m_impl.Stop(); }
707 
708  bool EnterConfigurationMode() {
709  return m_impl.EnterConfigurationMode();
710  }
711  bool ExitConfigurationMode() {
712  return m_impl.ExitConfigurationMode();
713  }
714 
715  // Various parameters to control the behaviour
716  bool SetShortName(const std::string &name) {
717  return m_impl.SetShortName(name);
718  }
719 
720  std::string ShortName() const { return m_impl.ShortName(); }
721  bool SetLongName(const std::string &name) {
722  return m_impl.SetLongName(name);
723  }
724 
725  std::string LongName() const { return m_impl.LongName(); }
726 
727  uint8_t NetAddress() const { return m_impl.NetAddress(); }
728  bool SetNetAddress(uint8_t net_address) {
729  return m_impl.SetNetAddress(net_address);
730  }
731  bool SetSubnetAddress(uint8_t subnet_address) {
732  return m_impl.SetSubnetAddress(subnet_address);
733  }
734  uint8_t SubnetAddress() const {
735  return m_impl.SubnetAddress();
736  }
737 
738  uint8_t InputPortCount() const {
739  return m_impl.InputPortCount();
740  }
741 
742  bool SetInputPortUniverse(uint8_t port_id, uint8_t universe_id) {
743  return m_impl.SetInputPortUniverse(port_id, universe_id);
744  }
745  uint8_t GetInputPortUniverse(uint8_t port_id) const {
746  return m_impl.GetInputPortUniverse(port_id);
747  }
748  void DisableInputPort(uint8_t port_id) {
749  m_impl.DisableInputPort(port_id);
750  }
751  bool InputPortState(uint8_t port_id) const {
752  return m_impl.InputPortState(port_id);
753  }
754 
755  bool SetOutputPortUniverse(uint8_t port_id, uint8_t universe_id) {
756  return m_impl.SetOutputPortUniverse(port_id, universe_id);
757  }
758  uint8_t GetOutputPortUniverse(uint8_t port_id) {
759  return m_impl.GetOutputPortUniverse(port_id);
760  }
761  void DisableOutputPort(uint8_t port_id) {
762  m_impl.DisableOutputPort(port_id);
763  }
764  bool OutputPortState(uint8_t port_id) const {
765  return m_impl.OutputPortState(port_id);
766  }
767 
768  void SetBroadcastThreshold(unsigned int threshold) {
769  m_impl.SetBroadcastThreshold(threshold);
770  }
771 
772  bool SetMergeMode(uint8_t port_id, artnet_merge_mode merge_mode) {
773  return m_impl.SetMergeMode(port_id, merge_mode);
774  }
775 
776  // Poll, this should be called periodically if we're sending data.
777  bool SendPoll() {
778  return m_impl.SendPoll();
779  }
780 
781  // The following apply to Input Ports (those which send data)
782  bool SendDMX(uint8_t port_id, const ola::DmxBuffer &buffer) {
783  return m_impl.SendDMX(port_id, buffer);
784  }
785 
789  void RunFullDiscovery(uint8_t port_id,
791 
795  void RunIncrementalDiscovery(uint8_t port_id,
797 
801  void SendRDMRequest(uint8_t port_id,
802  ola::rdm::RDMRequest *request,
803  ola::rdm::RDMCallback *on_complete);
804 
805  /*
806  * @brief This handler is called if we receive ArtTod packets and a discovery
807  * process isn't running.
808  */
809  bool SetUnsolicitedUIDSetHandler(
810  uint8_t port_id,
812  return m_impl.SetUnsolicitedUIDSetHandler(port_id, on_tod);
813  }
814  void GetSubscribedNodes(
815  uint8_t port_id,
816  std::vector<ola::network::IPV4Address> *node_addresses) {
817  m_impl.GetSubscribedNodes(port_id, node_addresses);
818  }
819 
820  // The following apply to Output Ports (those which receive data);
821  bool SetDMXHandler(uint8_t port_id,
822  DmxBuffer *buffer,
823  ola::Callback0<void> *handler) {
824  return m_impl.SetDMXHandler(port_id, buffer, handler);
825  }
826  bool SendTod(uint8_t port_id, const ola::rdm::UIDSet &uid_set) {
827  return m_impl.SendTod(port_id, uid_set);
828  }
829  bool SetOutputPortRDMHandlers(
830  uint8_t port_id,
831  ola::Callback0<void> *on_discover,
832  ola::Callback0<void> *on_flush,
833  ola::Callback2<void,
835  ola::rdm::RDMCallback*> *on_rdm_request) {
836  return m_impl.SetOutputPortRDMHandlers(port_id,
837  on_discover,
838  on_flush,
839  on_rdm_request);
840  }
841 
842  // Time Code methods
843  bool SendTimeCode(const ola::timecode::TimeCode &timecode) {
844  return m_impl.SendTimeCode(timecode);
845  }
846 
847  private:
848  ArtNetNodeImpl m_impl;
849  std::vector<ArtNetNodeImplRDMWrapper*> m_wrappers;
850  std::vector<ola::rdm::DiscoverableQueueingRDMController*> m_controllers;
851 
856  bool CheckInputPortId(uint8_t port_id);
857 
859 };
860 } // namespace artnet
861 } // namespace plugin
862 } // namespace ola
863 #endif // PLUGINS_ARTNET_ARTNETNODE_H_
Represents a set of RDM UIDs.
Definition: UIDSet.h:48
Definitions and Interfaces to implement an RDMController that sends a single message at a time...
Definition: ArtNetNode.h:65
void RunIncrementalDiscovery(ola::rdm::RDMDiscoveryCallback *callback)
Start an incremental discovery operation.
Definition: ArtNetNode.h:682
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
Creates dummy copy constructor and assignment operator declarations.
Definition: Macro.h:44
The interface for UDPSockets.
Definition: Socket.h:48
The interface that can send RDM commands, as well as perform discovery operations.
Definition: RDMControllerInterface.h:104
RDM Commands that represent requests (GET, SET or DISCOVER).
Definition: RDMCommand.h:234
Used to hold a single universe of DMX data.
Definition: DmxBuffer.h:49
A set of UIDs.
Definition: ArtNetPackets.h:252
A class used to hold a single universe of DMX data.
Definition: ArtNetNode.h:83
Definition: TimeCode.h:33
The base class that all RDM requests & responses inherit from.
Definition: RDMCommand.h:59
The interface for the SelectServer.
Definition: SelectServerInterface.h:42
Represents a IPv4 Address.
Definition: IPV4Address.h:55
The actual Art-Net Node.
Definition: ArtNetNode.h:697
Definition: Interface.h:35
An RDM Controller that queues messages and only sends a single message at a time. ...
The base class for all 1 argument callbacks.
Definition: Callback.h:982
The raw data for a RDM message and its associated timing information.
Definition: RDMFrame.h:40
Represents an IPv4 Address.
Holds the final state of an RDM request.
Definition: RDMReply.h:43
void RunFullDiscovery(ola::rdm::RDMDiscoveryCallback *callback)
Start a full discovery operation.
Definition: ArtNetNode.h:678
void SendRDMRequest(ola::rdm::RDMRequest *request, ola::rdm::RDMCallback *on_complete)
Send a RDM command.
Definition: ArtNetNode.h:673
A 2 argument callback which can be called multiple times.
Definition: Callback.h:1895
Represents a RDM UID.
Definition: UID.h:57
The namespace containing all OLA symbols.
Definition: Credentials.cpp:44
Represents a point in time with microsecond accuracy.
Definition: Clock.h:191
A 1 argument callback which can be called multiple times.
Definition: Callback.h:992
Classes that represent RDM commands.