Open Lighting Architecture
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DmxTriWidget.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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15  *
16  * DmxTriWidget.h
17  * The Jese DMX-TRI/RDM-TRI widget.
18  * Copyright (C) 2010 Simon Newton
19  */
20 
21 #ifndef PLUGINS_USBPRO_DMXTRIWIDGET_H_
22 #define PLUGINS_USBPRO_DMXTRIWIDGET_H_
23 
24 #include <map>
25 #include <string>
26 #include <queue>
27 #include "ola/Callback.h"
28 #include "ola/DmxBuffer.h"
31 #include "ola/rdm/UIDSet.h"
32 #include "ola/thread/SchedulerInterface.h"
33 #include "plugins/usbpro/BaseUsbProWidget.h"
34 
35 namespace ola {
36 namespace plugin {
37 namespace usbpro {
38 
39 using std::queue;
40 
41 
42 /*
43  * A DMX TRI Widget implementation. We separate the Widget from the
44  * implementation so we can leverage the QueueingRDMController.
45  */
48  public:
50  ola::io::ConnectedDescriptor *descriptor,
51  bool use_raw_rdm);
53 
54  void UseRawRDM(bool use_raw_rdm) { m_use_raw_rdm = use_raw_rdm; }
55 
56  void Stop();
57 
58  bool SendDMX(const DmxBuffer &buffer);
59  void SendRDMRequest(const ola::rdm::RDMRequest *request,
60  ola::rdm::RDMCallback *on_complete);
63 
64  private:
65  typedef enum {
66  SINGLE_TX_COMMAND_ID = 0x21,
67  DISCOVER_AUTO_COMMAND_ID = 0x33,
68  DISCOVER_STATUS_COMMAND_ID = 0x34,
69  REMOTE_UID_COMMAND_ID = 0x35,
70  RAW_RDM_COMMAND_ID = 0x37,
71  REMOTE_GET_COMMAND_ID = 0x38,
72  REMOTE_SET_COMMAND_ID = 0x39,
73  QUEUED_GET_COMMAND_ID = 0x3a,
74  SET_FILTER_COMMAND_ID = 0x3d,
75 
76  RESERVED_COMMAND_ID = 0xff,
77  } TriCommandId;
78 
79  typedef enum {
80  NO_DISCOVERY_ACTION,
81  DISCOVER_AUTO_REQUIRED,
82  DISCOVER_STATUS_REQUIRED,
83  FETCH_UID_REQUIRED,
84  } TriDiscoveryState;
85 
87  std::map<const ola::rdm::UID, uint8_t> m_uid_index_map;
88  uint8_t m_uid_count;
89  uint16_t m_last_esta_id;
90  bool m_use_raw_rdm;
91 
92  // State for sending DMX
93  DmxBuffer m_outgoing_dmx;
94 
95  // State for handling RDM discovery
96  ola::thread::timeout_id m_disc_stat_timeout_id;
97  ola::rdm::RDMDiscoveryCallback *m_discovery_callback;
98  TriDiscoveryState m_discovery_state;
99 
100  // State for sending RDM Gets/Sets
101  // This holds pointers to the RDMRequest and Callback that is queued or in
102  // flight.
103  ola::rdm::RDMCallback *m_rdm_request_callback;
104  const ola::rdm::RDMRequest *m_pending_rdm_request;
105  uint8_t m_transaction_number;
106  // The command id that we expect to see in the response.
107  uint8_t m_last_command, m_expected_command;
108 
109  void SendDMXBuffer();
110  void SendQueuedRDMCommand();
111  void RunDiscoveryCallback(ola::rdm::RDMDiscoveryCallback *callback);
112  bool CheckDiscoveryStatus();
113  void HandleMessage(uint8_t label,
114  const uint8_t *data,
115  unsigned int length);
116  void SendDiscoveryStart();
117  void SendDiscoveryStat();
118  void FetchNextUID();
119  bool IsDUBRequest(const ola::rdm::RDMRequest *request);
120  void SendRawRDMRequest();
121  void DispatchRequest();
122  void DispatchQueuedGet();
123  void StopDiscovery();
124 
125  void HandleSingleTXResponse(uint8_t return_code);
126  void HandleDiscoveryAutoResponse(uint8_t return_code,
127  const uint8_t *data,
128  unsigned int length);
129  void HandleDiscoverStatResponse(uint8_t return_code,
130  const uint8_t *data,
131  unsigned int length);
132  void HandleRemoteUIDResponse(uint8_t return_code,
133  const uint8_t *data,
134  unsigned int length);
135  void HandleRawRDMResponse(uint8_t return_code,
136  const uint8_t *data,
137  unsigned int length);
138  void HandleRemoteRDMResponse(uint8_t return_code,
139  const uint8_t *data,
140  unsigned int length);
141  void HandleQueuedGetResponse(uint8_t return_code,
142  const uint8_t *data,
143  unsigned int length);
144  void HandleGenericRDMResponse(uint8_t return_code,
145  uint16_t pid,
146  const uint8_t *data,
147  unsigned int length);
148  void HandleSetFilterResponse(uint8_t return_code,
149  const uint8_t *data,
150  unsigned int length);
151  bool PendingTransaction() const;
152  void MaybeSendNextRequest();
153  void HandleRDMError(ola::rdm::rdm_response_code error_code);
154  bool SendCommandToTRI(uint8_t label, const uint8_t *data,
155  unsigned int length);
156  bool TriToOlaReturnCode(uint8_t return_code,
157  ola::rdm::rdm_response_code *code);
158  bool ReturnCodeToNackReason(uint8_t return_code,
159  ola::rdm::rdm_nack_reason *reason);
160 
161  typedef enum {
162  EC_NO_ERROR = 0,
163  EC_CONSTRAINT = 1,
164  EC_UNKNOWN_COMMAND = 2,
165  EC_INVALID_OPTION = 3,
166  EC_FRAME_FORMAT = 4,
167  EC_DATA_TOO_LONG = 5,
168  EC_DATA_MISSING = 6,
169  EC_SYSTEM_MODE = 7,
170  EC_SYSTEM_BUSY = 8,
171  EC_DATA_CHECKSUM = 0x0a,
172  EC_INCOMPATIBLE = 0x0b,
173  EC_RESPONSE_TIME = 0x10,
174  EC_RESPONSE_WAIT = 0x11,
175  EC_RESPONSE_MORE = 0x12,
176  EC_RESPONSE_TRANSACTION = 0x13,
177  EC_RESPONSE_SUB_DEVICE = 0x14,
178  EC_RESPONSE_FORMAT = 0x15,
179  EC_RESPONSE_CHECKSUM = 0x16,
180  EC_RESPONSE_NONE = 0x18,
181  EC_RESPONSE_IDENTITY = 0x1a,
182  EC_RESPONSE_MUTE = 0x1b,
183  EC_RESPONSE_DISCOVERY = 0x1c,
184  EC_RESPONSE_UNEXPECTED = 0x1d,
185  EC_UNKNOWN_PID = 0x20,
186  EC_FORMAT_ERROR = 0x21,
187  EC_HARDWARE_FAULT = 0x22,
188  EC_PROXY_REJECT = 0x23,
189  EC_WRITE_PROTECT = 0x24,
190  EC_UNSUPPORTED_COMMAND_CLASS = 0x25,
191  EC_OUT_OF_RANGE = 0x26,
192  EC_BUFFER_FULL = 0x27,
193  EC_FRAME_OVERFLOW = 0x28,
194  EC_SUBDEVICE_UNKNOWN = 0x29,
195  EC_PROXY_BUFFER_FULL = 0x2a, // this isn't included in the docs
196  } dmx_tri_error_codes;
197 
198  static const unsigned int DATA_OFFSET = 2; // first two bytes are CI & RC
199  static const uint8_t EXTENDED_COMMAND_LABEL = 88; // 'X'
200 
201  // The ms delay between checking on the RDM discovery process
202  static const unsigned int RDM_STATUS_INTERVAL_MS = 100;
203 };
204 
205 
206 /*
207  * A DMX TRI Widget
208  */
211  public:
213  ola::io::ConnectedDescriptor *descriptor,
214  unsigned int queue_size = 20,
215  bool use_raw_rdm = false);
216  ~DmxTriWidget();
217  void UseRawRDM(bool use_raw_rdm) { m_impl->UseRawRDM(use_raw_rdm); }
218 
219  void Stop() { m_impl->Stop(); }
220 
221  bool SendDMX(const DmxBuffer &buffer) const {
222  return m_impl->SendDMX(buffer);
223  }
224 
226  ola::rdm::RDMCallback *on_complete) {
227  m_controller->SendRDMRequest(request, on_complete);
228  }
229 
231  m_controller->RunFullDiscovery(callback);
232  }
233 
234  void RunIncrementalDiscovery(ola::rdm::RDMDiscoveryCallback *callback) {
235  m_controller->RunIncrementalDiscovery(callback);
236  }
237 
238  ola::io::ConnectedDescriptor *GetDescriptor() const {
239  return m_impl->GetDescriptor();
240  }
241 
242  private:
243  // we need to control the order of construction & destruction here so these
244  // are pointers.
245  DmxTriWidgetImpl *m_impl;
247 
248  void ResumeRDMCommands() {
249  m_controller->Resume();
250  }
251 };
252 } // namespace usbpro
253 } // namespace plugin
254 } // namespace ola
255 #endif // PLUGINS_USBPRO_DMXTRIWIDGET_H_