Open Lighting Architecture  0.9.4
 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"
40 #include "ola/rdm/UIDSet.h"
41 #include "ola/timecode/TimeCode.h"
42 #include "plugins/artnet/ArtNetPackets.h"
43 
44 namespace ola {
45 namespace plugin {
46 namespace artnet {
47 
48 
49 // The directions are the opposite from what OLA uses
50 typedef enum {
51  ARTNET_INPUT_PORT, // sends ArtNet data
52  ARTNET_OUTPUT_PORT, // receives ArtNet data
53 } artnet_port_type;
54 
55 typedef enum {
56  ARTNET_MERGE_HTP, // default
57  ARTNET_MERGE_LTP,
58 } artnet_merge_mode;
59 
60 
61 // This can be passed to SetPortUniverse to disable ports
62 static const uint8_t ARTNET_DISABLE_PORT = 0xf0;
63 
65  public:
67  : always_broadcast(false),
68  use_limited_broadcast_address(false),
69  rdm_queue_size(20),
70  broadcast_threshold(30),
71  input_port_count(4) {
72  }
73 
74  bool always_broadcast;
75  bool use_limited_broadcast_address;
76  unsigned int rdm_queue_size;
77  unsigned int broadcast_threshold;
78  uint8_t input_port_count;
79 };
80 
81 
83  public:
93  const ArtNetNodeOptions &options,
94  ola::network::UDPSocketInterface *socket = NULL);
95 
99  virtual ~ArtNetNodeImpl();
100 
104  bool Start();
105 
109  bool Stop();
110 
127  bool EnterConfigurationMode();
128 
134  bool ExitConfigurationMode();
135 
136 
137  // Various parameters to control the behaviour
142  bool SetShortName(const std::string &name);
143  std::string ShortName() const { return m_short_name; }
144 
149  bool SetLongName(const std::string &name);
150  std::string LongName() const { return m_long_name; }
151 
156  bool SetNetAddress(uint8_t net_address);
157  uint8_t NetAddress() const { return m_net_address; }
158 
163  bool SetSubnetAddress(uint8_t subnet_address);
164  uint8_t SubnetAddress() const {
165  return m_output_ports[0].universe_address >> 4;
166  }
167 
172  uint8_t InputPortCount() const;
173 
177  bool SetInputPortUniverse(uint8_t port_id, uint8_t universe_id);
178 
187  uint8_t GetInputPortUniverse(uint8_t port_id) const;
188 
193  void DisableInputPort(uint8_t port_id);
194 
201  bool InputPortState(uint8_t port_id) const;
202 
208  bool SetOutputPortUniverse(uint8_t port_id, uint8_t universe_id);
209 
215  uint8_t GetOutputPortUniverse(uint8_t port_id);
216 
221  void DisableOutputPort(uint8_t port_id);
222 
229  bool OutputPortState(uint8_t port_id) const;
230 
231  void SetBroadcastThreshold(unsigned int threshold) {
232  m_broadcast_threshold = threshold;
233  }
234 
240  bool SetMergeMode(uint8_t port_id, artnet_merge_mode merge_mode);
241 
247  bool SendPoll();
248 
249  // The following apply to Input Ports (those which send data)
256  bool SendDMX(uint8_t port_id, const ola::DmxBuffer &buffer);
257 
266  void RunFullDiscovery(uint8_t port_id,
268 
278  void RunIncrementalDiscovery(uint8_t port_id,
280 
293  void SendRDMRequest(uint8_t port_id,
294  const ola::rdm::RDMRequest *request,
295  ola::rdm::RDMCallback *on_complete);
296 
304  uint8_t port_id,
306 
315  void GetSubscribedNodes(
316  uint8_t port_id,
317  std::vector<ola::network::IPV4Address> *node_addresses);
318 
319  // The following apply to Output Ports (those which receive data);
327  bool SetDMXHandler(uint8_t port_id,
328  DmxBuffer *buffer,
329  ola::Callback0<void> *handler);
330 
336  bool SendTod(uint8_t port_id, const ola::rdm::UIDSet &uid_set);
337 
342  uint8_t port_id,
343  ola::Callback0<void> *on_discover,
344  ola::Callback0<void> *on_flush,
345  ola::Callback2<void,
346  const ola::rdm::RDMRequest*,
347  ola::rdm::RDMCallback*> *on_rdm_request);
348 
352  bool SendTimeCode(const ola::timecode::TimeCode &timecode);
353 
354  private:
355  class InputPort;
356  typedef std::vector<InputPort*> InputPorts;
357 
358  // map a uid to a IP address and the number of times we've missed a
359  // response.
360  typedef std::map<ola::rdm::UID,
361  std::pair<ola::network::IPV4Address, uint8_t> > uid_map;
362 
363  enum { MAX_MERGE_SOURCES = 2 };
364 
365  struct DMXSource {
366  DmxBuffer buffer;
367  TimeStamp timestamp;
369  };
370 
371  // Output Ports receive ArtNet data
372  struct OutputPort {
373  uint8_t universe_address;
374  uint8_t sequence_number;
375  bool enabled;
376  artnet_merge_mode merge_mode;
377  bool is_merging;
378  DMXSource sources[MAX_MERGE_SOURCES];
379  DmxBuffer *buffer;
380  std::map<ola::rdm::UID, ola::network::IPV4Address> uid_map;
381  Callback0<void> *on_data;
382  Callback0<void> *on_discover;
383  Callback0<void> *on_flush;
384  ola::Callback2<void,
385  const ola::rdm::RDMRequest*,
386  ola::rdm::RDMCallback*> *on_rdm_request;
387  };
388 
389  bool m_running;
390  uint8_t m_net_address; // this is the 'net' portion of the Artnet address
391  bool m_send_reply_on_change;
392  std::string m_short_name;
393  std::string m_long_name;
394  unsigned int m_broadcast_threshold;
395  unsigned int m_unsolicited_replies;
397  bool m_always_broadcast;
398  bool m_use_limited_broadcast_address;
399 
400  // The following keep track of "Configuration mode"
401  bool m_in_configuration_mode;
402  bool m_artpoll_required;
403  bool m_artpollreply_required;
404 
405  InputPorts m_input_ports;
406  OutputPort m_output_ports[ARTNET_MAX_PORTS];
407  ola::network::Interface m_interface;
408  std::auto_ptr<ola::network::UDPSocketInterface> m_socket;
409 
413  void SocketReady();
414 
420  bool SendPollIfAllowed();
421 
429  bool SendPollReplyIfRequired();
430 
434  bool SendPollReply(const ola::network::IPV4Address &destination);
435 
439  bool SendIPReply(const ola::network::IPV4Address &destination);
440 
444  void HandlePacket(const ola::network::IPV4Address &source_address,
445  const artnet_packet &packet,
446  unsigned int packet_size);
447 
451  void HandlePollPacket(const ola::network::IPV4Address &source_address,
452  const artnet_poll_t &packet,
453  unsigned int packet_size);
454 
458  void HandleReplyPacket(const ola::network::IPV4Address &source_address,
459  const artnet_reply_t &packet,
460  unsigned int packet_size);
461 
465  void HandleDataPacket(const ola::network::IPV4Address &source_address,
466  const artnet_dmx_t &packet,
467  unsigned int packet_size);
468 
472  void HandleTodRequest(const ola::network::IPV4Address &source_address,
473  const artnet_todrequest_t &packet,
474  unsigned int packet_size);
475 
479  void HandleTodData(const ola::network::IPV4Address &source_address,
480  const artnet_toddata_t &packet,
481  unsigned int packet_size);
482 
486  void HandleTodControl(const ola::network::IPV4Address &source_address,
487  const artnet_todcontrol_t &packet,
488  unsigned int packet_size);
489 
493  void HandleRdm(const ola::network::IPV4Address &source_address,
494  const artnet_rdm_t &packet,
495  unsigned int packet_size);
496 
500  void RDMRequestCompletion(ola::network::IPV4Address destination,
501  uint8_t port_id,
502  uint8_t universe_address,
503  ola::rdm::rdm_response_code code,
504  const ola::rdm::RDMResponse *response,
505  const std::vector<std::string> &packets);
506 
516  void HandleRDMResponse(InputPort *port,
517  const std::string &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 
656  DISALLOW_COPY_AND_ASSIGN(ArtNetNodeImpl);
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 
682  void RunIncrementalDiscovery(ola::rdm::RDMDiscoveryCallback *callback) {
683  m_impl->RunIncrementalDiscovery(m_port_id, callback);
684  }
685 
686  private:
687  ArtNetNodeImpl *m_impl;
688  uint8_t m_port_id;
689 
690  DISALLOW_COPY_AND_ASSIGN(ArtNetNodeImplRDMWrapper);
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  const 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,
834  const ola::rdm::RDMRequest*,
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 
858  DISALLOW_COPY_AND_ASSIGN(ArtNetNode);
859 };
860 } // namespace artnet
861 } // namespace plugin
862 } // namespace ola
863 #endif // PLUGINS_ARTNET_ARTNETNODE_H_