Open Lighting Architecture  0.9.3
 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 
411  ArtNetNodeImpl& operator=(const ArtNetNodeImpl&);
412 
416  void SocketReady();
417 
423  bool SendPollIfAllowed();
424 
432  bool SendPollReplyIfRequired();
433 
437  bool SendPollReply(const ola::network::IPV4Address &destination);
438 
442  bool SendIPReply(const ola::network::IPV4Address &destination);
443 
447  void HandlePacket(const ola::network::IPV4Address &source_address,
448  const artnet_packet &packet,
449  unsigned int packet_size);
450 
454  void HandlePollPacket(const ola::network::IPV4Address &source_address,
455  const artnet_poll_t &packet,
456  unsigned int packet_size);
457 
461  void HandleReplyPacket(const ola::network::IPV4Address &source_address,
462  const artnet_reply_t &packet,
463  unsigned int packet_size);
464 
468  void HandleDataPacket(const ola::network::IPV4Address &source_address,
469  const artnet_dmx_t &packet,
470  unsigned int packet_size);
471 
475  void HandleTodRequest(const ola::network::IPV4Address &source_address,
476  const artnet_todrequest_t &packet,
477  unsigned int packet_size);
478 
482  void HandleTodData(const ola::network::IPV4Address &source_address,
483  const artnet_toddata_t &packet,
484  unsigned int packet_size);
485 
489  void HandleTodControl(const ola::network::IPV4Address &source_address,
490  const artnet_todcontrol_t &packet,
491  unsigned int packet_size);
492 
496  void HandleRdm(const ola::network::IPV4Address &source_address,
497  const artnet_rdm_t &packet,
498  unsigned int packet_size);
499 
503  void RDMRequestCompletion(ola::network::IPV4Address destination,
504  uint8_t port_id,
505  uint8_t universe_address,
506  ola::rdm::rdm_response_code code,
507  const ola::rdm::RDMResponse *response,
508  const std::vector<std::string> &packets);
509 
519  void HandleRDMResponse(InputPort *port,
520  const std::string &rdm_data,
521  const ola::network::IPV4Address &source_address);
522 
526  void HandleIPProgram(const ola::network::IPV4Address &source_address,
527  const artnet_ip_prog_t &packet,
528  unsigned int packet_size);
529 
533  void PopulatePacketHeader(artnet_packet *packet, uint16_t op_code);
534 
541  bool SendPacket(const artnet_packet &packet,
542  unsigned int size,
543  const ola::network::IPV4Address &destination);
544 
549  void TimeoutRDMRequest(InputPort *port);
550 
554  bool SendRDMCommand(const ola::rdm::RDMCommand &command,
555  const ola::network::IPV4Address &destination,
556  uint8_t universe);
557 
561  void UpdatePortFromSource(OutputPort *port, const DMXSource &source);
562 
566  bool CheckPacketVersion(const ola::network::IPV4Address &source_address,
567  const std::string &packet_type,
568  uint16_t version);
569 
573  bool CheckPacketSize(const ola::network::IPV4Address &source_address,
574  const std::string &packet_type,
575  unsigned int actual_size,
576  unsigned int expected_size);
577 
578  // methods for accessing Input & Output ports
582  InputPort *GetInputPort(uint8_t port_id, bool warn = true);
583 
587  const InputPort *GetInputPort(uint8_t port_id) const;
588 
592  InputPort *GetEnabledInputPort(uint8_t port_id, const std::string &action);
593 
597  OutputPort *GetOutputPort(uint8_t port_id);
598 
602  const OutputPort *GetOutputPort(uint8_t port_id) const;
603 
607  OutputPort *GetEnabledOutputPort(uint8_t port_id, const std::string &action);
608 
612  void UpdatePortFromTodPacket(InputPort *port,
613  const ola::network::IPV4Address &source_address,
614  const artnet_toddata_t &packet,
615  unsigned int packet_size);
616 
620  void ReleaseDiscoveryLock(InputPort *port);
621 
628  bool StartDiscoveryProcess(InputPort *port,
630 
634  bool InitNetwork();
635 
636  static const char ARTNET_ID[];
637  static const uint16_t ARTNET_PORT = 6454;
638  static const uint16_t OEM_CODE = 0x0431;
639  static const uint16_t ARTNET_VERSION = 14;
640  // after not receiving a PollReply after this many seconds we declare the
641  // node as dead. This is set to 3x the POLL_INTERVAL in ArtNetDevice.
642  static const uint8_t NODE_CODE = 0x00;
643  static const uint16_t MAX_UIDS_PER_UNIVERSE = 0xffff;
644  static const uint8_t RDM_VERSION = 0x01; // v1.0 standard baby!
645  static const uint8_t TOD_FLUSH_COMMAND = 0x01;
646  static const unsigned int MERGE_TIMEOUT = 10; // As per the spec
647  // seconds after which a node is marked as inactive for the dmx merging
648  static const unsigned int NODE_TIMEOUT = 31;
649  // mseconds we wait for a TodData packet before declaring a node missing
650  static const unsigned int RDM_TOD_TIMEOUT_MS = 4000;
651  // Number of missed TODs before we decide a UID has gone
652  static const unsigned int RDM_MISSED_TODDATA_LIMIT = 3;
653  // The maximum number of requests we'll allow in the queue. This is a per
654  // port (universe) limit.
655  static const unsigned int RDM_REQUEST_QUEUE_LIMIT = 100;
656  // How long to wait for a response to an RDM Request
657  static const unsigned int RDM_REQUEST_TIMEOUT_MS = 2000;
658 };
659 
660 
667  public:
668  ArtNetNodeImplRDMWrapper(ArtNetNodeImpl *impl, uint8_t port_id):
669  m_impl(impl),
670  m_port_id(port_id) {
671  }
673 
675  ola::rdm::RDMCallback *on_complete) {
676  m_impl->SendRDMRequest(m_port_id, request, on_complete);
677  }
678 
680  m_impl->RunFullDiscovery(m_port_id, callback);
681  }
682 
683  void RunIncrementalDiscovery(ola::rdm::RDMDiscoveryCallback *callback) {
684  m_impl->RunIncrementalDiscovery(m_port_id, callback);
685  }
686 
687  private:
688  ArtNetNodeImpl *m_impl;
689  uint8_t m_port_id;
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  const 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,
833  const ola::rdm::RDMRequest*,
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 } // namespace artnet
858 } // namespace plugin
859 } // namespace ola
860 #endif // PLUGINS_ARTNET_ARTNETNODE_H_