WIP
DirectOutput framework for virtual pinball cabinets WIP
Go to:
Overview 
DirectStripControllerApi.cs
Go to the documentation of this file.
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.IO.Ports;
6 using System.Threading;
8 
9 namespace DirectOutput.Cab.Out.AdressableLedStrip
10 {
15  {
16  private static readonly string[] ControllerNameBase = { "WS2811 Strip Controller", "Direct Strip Controller" };
17 
18 
22  public void ClearData()
23  {
24  lock (FT245RLocker)
25  {
26  if (FT245R != null)
27  {
28  try
29  {
30  uint Dummy = 0;
31  FT245R.Write(new byte[] { (byte)'C' }, 1, ref Dummy);
32  }
33  catch { Close(); }
34  }
35  }
36  }
37 
42  public void DisplayData(int Length)
43  {
44  lock (FT245RLocker)
45  {
46  if (FT245R != null)
47  {
48  try
49  {
50  uint Dummy = 0;
51  FT245R.Write(new byte[] { (byte)'O', (byte)(Length / 256), (byte)(Length & 255) }, 3, ref Dummy);
52  }
53  catch { Close(); }
54  }
55  }
56  }
57 
62  public void SetAndDisplayData(byte[] Data)
63  {
64  lock (FT245RLocker)
65  {
66  SetData(Data);
67  DisplayData(Data.Length);
68  }
69  }
70 
71 
72 
77  public void SetData(byte[] Data)
78  {
79  byte[] Header = { (byte)'R', (byte)(Data.Length / 256), (byte)(Data.Length & 255) };
80  lock (FT245RLocker)
81  {
82  if (FT245R != null)
83  {
84  try
85  {
86  uint Dummy = 0;
87  FT245R.Write(Header, 3, ref Dummy);
88  FT245R.Write(Data, Data.Length, ref Dummy);
89  }
90  catch { Close(); }
91  }
92  }
93  }
94 
95 
96  public byte[] ReadData(int Length)
97  {
98  byte[] Data = new byte[Length];
99  byte[] Header = { (byte)'S', (byte)(Length / 256), (byte)(Length & 255) };
100  lock (FT245RLocker)
101  {
102  if (FT245R != null)
103  {
104  try
105  {
106  uint Dummy = 0;
107  FT245R.CharReceived-=new EventHandler<EventArgs>(FT245R_CharReceived);
108  FT245R.Write(Header, 3, ref Dummy);
109 
110 
111  uint BytesRead=0;
112  FT245R.Read(Data, ((uint)Length), ref BytesRead);
113 
114 
115  FT245R.CharReceived += new EventHandler<EventArgs>(FT245R_CharReceived);
116 
117  }
118  catch { Close(); }
119  }
120  }
121  return Data;
122  }
123 
124 
125 
130  public void SetAndDisplayPackedData(byte[] Data)
131  {
132  lock (FT245RLocker)
133  {
134  SetPackedData(Data);
135  DisplayData(Data.Length);
136  }
137  }
138 
143  public void SetPackedData(byte[] Data)
144  {
145 
146  int DataPos = 0;
147 
148  //Calc number of bytes to pack. Truncate data to a length which is divideable by 3.
149  int DataLength = Data.Length;
150  if (DataLength % 3 != 0)
151  {
152  DataLength -= (DataLength % 3);
153  }
154 
155  //Create array for packed data (I hope the calc für the max size of the packed data is correct)
156  byte[] Packed = new byte[(int)(DataLength + ((double)DataLength / 127) + 2)];
157  int PackedPos = 3;
158 
159  int BlockStartPos = 0;
160  byte BlockSize = 0;
161 
162  while (DataPos < DataLength)
163  {
164 
165  BlockStartPos = PackedPos++; //Store startpos of block
166  Packed[PackedPos++] = Data[DataPos++]; //Get first 3 bytes
167  Packed[PackedPos++] = Data[DataPos++];
168  Packed[PackedPos++] = Data[DataPos++];
169  BlockSize = 1;
170 
171  if (DataPos >= DataLength)
172  {
173  //reached the end of the data
174  Packed[BlockStartPos] = BlockSize; //Set the size of the block (1 triplet)
175  }
176  else
177  {
178  //not yet the end of the data
179 
180  //Check if the next bytes are the same as the first 3 bytes
181  if (Packed[BlockStartPos + 1] != Data[DataPos] || Packed[BlockStartPos + 2] != Data[DataPos + 1] || Packed[BlockStartPos + 3] != Data[DataPos + 2])
182  {
183  //Data is different, build block of org data
184 
185  while (BlockSize < 127 && DataPos < DataLength && ((DataPos >= DataLength - 3) || (Data[DataPos] != Data[DataPos + 3] || Data[DataPos + 1] != Data[DataPos + 4] || Data[DataPos + 2] != Data[DataPos + 5])))
186  {
187  Packed[PackedPos++] = Data[DataPos++]; //Get next 3 bytes
188  Packed[PackedPos++] = Data[DataPos++];
189  Packed[PackedPos++] = Data[DataPos++];
190  BlockSize++;
191  }
192  Packed[BlockStartPos] = BlockSize; //Set the number of triplets for the block
193 
194  }
195  else
196  {
197  //Data is the same, build block of packed data
198  while (BlockSize < 127 && DataPos < DataLength && Packed[BlockStartPos + 1] == Data[DataPos] && Packed[BlockStartPos + 2] == Data[DataPos + 1] && Packed[BlockStartPos + 3] == Data[DataPos + 2])
199  {
200  DataPos += 3;
201  BlockSize++;
202  }
203  Packed[BlockStartPos] = (byte)(BlockSize + 128); //Set the number of repetions for the block, add 128 to mark the packed data
204 
205  }
206  }
207 
208  }
209 
210  Packed[PackedPos++] = 0; //Add 0 byte to mark the end of the data
211 
212  byte[] Header = { (byte)'P', (byte)(PackedPos / 256), (byte)(PackedPos & 255) };
213  lock (FT245RLocker)
214  {
215  if (FT245R != null)
216  {
217  try
218  {
219  uint Dummy = 0;
220  FT245R.Write(Header, 3, ref Dummy);
221  FT245R.Write(Data, Data.Length, ref Dummy);
222  }
223  catch { Close(); }
224  }
225  }
226 
227 
228  }
229 
230 
231 
232 
233 
238 
243  public DirectStripControllerApi(int ControllerNumber)
244  {
245  Open(ControllerNumber);
246 
247  }
248 
249  private int _ControllerNumber;
250 
257  public int ControllerNumber
258  {
259  get { return _ControllerNumber; }
260  private set { _ControllerNumber = value; }
261  }
262 
263 
270  public bool DeviceIsPresent
271  {
272  get
273  {
274  uint Dummy = 0;
275  return FT245R != null && FT245R.GetRxBytesAvailable(ref Dummy) == FTDI.FT_STATUS.FT_OK;
276  }
277  }
278 
279 
280 
281 
282  FTDI FT245R;
283  private object FT245RLocker = new object();
284 
289  public void Open(int ControllerNumber)
290  {
291  lock (FT245RLocker)
292  {
293  Close();
294 
295  bool OK = false;
296 
297  string Desc = "";
298  this.ControllerNumber = ControllerNumber;
299 
300  FT245R = new FTDI();
301  FTDI.FT_STATUS FTStatus;
302 
303 
304 
305  //Get number of devices
306  uint DeviceCnt = 0;
307  FTStatus = FT245R.GetNumberOfDevices(ref DeviceCnt);
308 
309  if (FTStatus == FTDI.FT_STATUS.FT_OK && DeviceCnt > 0)
310  {
311  FTDI.FT_DEVICE_INFO_NODE[] Devices = new FTDI.FT_DEVICE_INFO_NODE[DeviceCnt];
312 
313  //for (uint i = 0; i < DeviceCnt; i++)
314  //{
315  // FTStatus = FT245R.OpenByIndex(i);
316  // // Log.Write("Open {0}: Result: {1}".Build(i, FTStatus.ToString()));
317  // if (FT245R.IsOpen)
318  // {
319  // string D = "";
320  // FT245R.GetDescription(out D);
321  // Log.Write("Desc: {0}".Build(D));
322  // try
323  // {
324  // FTStatus = FT245R.Close();
325  // Log.Write("Close {i}: Result: {1}".Build(i, FTStatus.ToString()));
326  // }
327  // catch { }
328  // }
329 
330  //}
331  //Log.Write("All listed");
332 
333  FTStatus = FT245R.GetDeviceList(Devices);
334  if (FTStatus == FTDI.FT_STATUS.FT_OK)
335  {
336 
337 
338  foreach (FTDI.FT_DEVICE_INFO_NODE DI in Devices)
339  {
340  if (DI != null && DI.Type == FTDI.FT_DEVICE.FT_DEVICE_232R)
341  {
342  if (ControllerNameBase.Any(N => DI.Description == N.Trim() + " " + ControllerNumber))
343  {
344 
345  Desc = DI.Description;
346  FT245R.CharReceived += new EventHandler<EventArgs>(FT245R_CharReceived);
347 
348  FTStatus = FT245R.OpenByLocation(DI.LocId);
349  if (FTStatus == FTDI.FT_STATUS.FT_OK)
350  {
351  FTStatus = FT245R.Purge(FTDI.FT_PURGE.FT_PURGE_RX + FTDI.FT_PURGE.FT_PURGE_TX);
352  if (FTStatus == FTDI.FT_STATUS.FT_OK)
353  {
354  OK = true;
355  break;
356  }
357  else
358  {
359  Log.Exception("Purge failed for WS2811StripController {0}. Error: {1}".Build(ControllerNumber, FTStatus.ToString()));
360  }
361  }
362  else
363  {
364  Log.Exception("Open failed for WS2811StripController {0}. Error: {1}".Build(ControllerNumber, FTStatus.ToString()));
365  }
366  }
367  }
368  }
369  }
370  else
371  {
372 
373  Log.Exception("Could not fetch devicelist for WS2811StripControllers. Error: {0}".Build(FTStatus.ToString()));
374  }
375  }
376 
377 
378  if (!OK)
379  {
380  if (!Desc.IsNullOrWhiteSpace())
381  {
382  Log.Warning("{0} detected, but could not open connection.".Build(Desc));
383  }
384  else
385  {
386  Log.Warning("Direct Strip Controller with number {0} not found.".Build(ControllerNumber));
387  }
388  Close();
389 
390  }
391  else
392  {
393  Log.Write("{0} detected and connection opend.".Build(Desc));
394  }
395  }
396  }
397 
398 
399  private int ErrorCorrectionCnt = 0;
400 
401  void FT245R_CharReceived(object sender, EventArgs e)
402  {
403  uint CharsToRead = 0;
404 
405  FT245R.GetRxBytesAvailable(ref CharsToRead);
406 
407  if (CharsToRead > 0)
408  {
409  uint BytesRead = 0;
410  byte[] Response = new Byte[CharsToRead];
411  FT245R.Read(Response, CharsToRead, ref BytesRead);
412 
413  bool OK = true;
414  for (int i = 0; i < BytesRead; i++)
415  {
416  if (Response[i] == 0x4e)
417  {
418  OK = false;
419  break;
420  }
421  }
422  if (!OK)
423  {
424  lock (FT245RLocker)
425  {
426  ErrorCorrectionCnt++;
427  if (ErrorCorrectionCnt <= 30)
428  {
429  Log.Warning("Received unexpected answer from Direct Strip Controller with number {0}. Will try to fix problem.".Build(ControllerNumber));
430  if (ErrorCorrectionCnt == 30)
431  {
432  Log.Write("No further warnings will be recorded for unexpected answers from this unit.");
433  }
434  }
435  FT245R.CharReceived -= new EventHandler<EventArgs>(FT245R_CharReceived);
436  uint Dummy = 0;
437  for (int i = 0; i < 2000; i++)
438  {
439  FT245R.Write(new byte[10], 10, ref Dummy);
440  Thread.Sleep(10);
441  CharsToRead = 0;
442  FT245R.GetRxBytesAvailable(ref CharsToRead);
443  if (CharsToRead > 0)
444  {
445  Thread.Sleep(10);
446  CharsToRead = 0;
447  FT245R.GetRxBytesAvailable(ref CharsToRead);
448  Response = new Byte[CharsToRead];
449  BytesRead = 0;
450  FT245R.Read(Response, CharsToRead, ref BytesRead);
451  break;
452  }
453 
454 
455  }
456  FT245R.CharReceived += new EventHandler<EventArgs>(FT245R_CharReceived);
457 
458  }
459 
460 
461  }
462  }
463  }
464 
465 
469  public void Close()
470  {
471  lock (FT245RLocker)
472  {
473  if (FT245R != null)
474  {
475  if (FT245R.IsOpen)
476  {
477  FT245R.Close();
478 
479  }
480  try
481  {
482  FT245R.CharReceived -= new EventHandler<EventArgs>(FT245R_CharReceived);
483  }
484  catch { }
485 
486  FT245R = null;
487  }
488  }
489  }
490 
491 
492 
497  public static List<int> GetAvailableControllerNumbers()
498  {
499  List<int> L = new List<int>();
500 
501  FTDI FTD2xxWrapper = new FTDI();
502  FTDI.FT_STATUS FTStatus;
503 
504  //Get number of devices
505  uint DeviceCnt = 0;
506  FTStatus = FTD2xxWrapper.GetNumberOfDevices(ref DeviceCnt);
507 
508  if (FTStatus == FTDI.FT_STATUS.FT_OK && DeviceCnt > 0)
509  {
510  FTDI.FT_DEVICE_INFO_NODE[] Devices = new FTDI.FT_DEVICE_INFO_NODE[DeviceCnt];
511 
512  FTStatus = FTD2xxWrapper.GetDeviceList(Devices);
513  if (FTStatus == FTDI.FT_STATUS.FT_OK)
514  {
515  foreach (FTDI.FT_DEVICE_INFO_NODE DI in Devices)
516  {
517  if (DI != null && DI.Type == FTDI.FT_DEVICE.FT_DEVICE_232R)
518  {
519  string B = ControllerNameBase.FirstOrDefault(N => DI.Description.StartsWith(N.Trim() + " "));
520  int ControllerNr = 0;
521  if (B != null && int.TryParse(DI.Description.Substring(B.Length), out ControllerNr))
522  {
523  if (ControllerNr > 0)
524  {
525  L.Add(ControllerNr);
526 
527  }
528  }
529  }
530  }
531  }
532  }
533  return L;
534  }
535 
536 
537 
538  }
539 }
const byte FT_PURGE_RX
Purge Rx buffer
Definition: FTD2XX_NET.cs:489
FT_STATUS Purge(UInt32 purgemask)
Purge data from the devices transmit and/or receive buffers.
Definition: FTD2XX_NET.cs:2849
FT_STATUS
Status values for FTDI devices.
Definition: FTD2XX_NET.cs:303
DirectStripControllerApi(int ControllerNumber)
Initializes a new instance of the DirectStripControllerApi class and opens a connection to the specif...
EventHandler< EventArgs > CharReceived
Occurs when the FDTI devices receives a byte.
Definition: FTD2XX_NET.cs:2491
FT_STATUS Write(byte[] dataBuffer, Int32 numBytesToWrite, ref UInt32 numBytesWritten)
Write data to an open FTDI device.
Definition: FTD2XX_NET.cs:2652
void Open(int ControllerNumber)
Opens a connection to the ledstrip controller with the specified controller number.
DirectStripControllerApi()
Initializes a new instance of the DirectStripControllerApi class.
FT_STATUS Read(byte[] dataBuffer, UInt32 numBytesToRead, ref UInt32 numBytesRead)
Read data from an open FTDI device.
Definition: FTD2XX_NET.cs:2556
static void Warning(string Message)
Writes a warning message to the log.
Definition: Log.cs:134
FT_STATUS GetNumberOfDevices(ref UInt32 devcount)
Gets the number of FTDI devices available.
Definition: FTD2XX_NET.cs:2044
bool IsOpen
Gets the open status of the device.
Definition: FTD2XX_NET.cs:6376
FT_STATUS GetDeviceList(FT_DEVICE_INFO_NODE[] devicelist)
Gets information on all of the FTDI devices available.
Definition: FTD2XX_NET.cs:2080
static void Write(string Message)
Writes the specified message to the logfile.
Definition: Log.cs:99
A simple logger used to record important events and exceptions.
Definition: Log.cs:14
void SetAndDisplayData(byte[] Data)
Sends the specified data to the ledstrip controller and displays the data.
The namespace DirectOutput.Cab contains all cabinet related classes like the Cabinet class itself...
Definition: Cab.cs:16
void DisplayData(int Length)
Sends a display data command to the ledstrip controller.
static List< int > GetAvailableControllerNumbers()
Gets a list of available ledstrip controller numbers.
void SetPackedData(byte[] Data)
Packs the specified data using a IFF like compression and send the data to the ledstrip controller...
DirectOutput.Cab.Out is the namespace for all output controller related classes like different output...
void Close()
Closes a currently open connection to a ledstrip controller.
void SetData(byte[] Data)
Sends the specified data to the ledstripn controller.
void ClearData()
Sends a clear data buffer command to the Ledstrip controller
Purge buffer constant definitions
Definition: FTD2XX_NET.cs:484
Namespace for the FTD2XX_NET class (used for communication with FTDI chips and for generic FTDI chip ...
const byte FT_PURGE_TX
Purge Tx buffer
Definition: FTD2XX_NET.cs:493
Type that holds device information for GetDeviceInformation method. Used with FT_GetDeviceInfo and FT...
Definition: FTD2XX_NET.cs:927
FT_DEVICE
List of FTDI device types
Definition: FTD2XX_NET.cs:862
FT_STATUS GetRxBytesAvailable(ref UInt32 RxQueue)
Gets the number of bytes available in the receive buffer.
Definition: FTD2XX_NET.cs:5421
FT_STATUS OpenByLocation(UInt32 location)
Opens the FTDI device at the specified physical location.
Definition: FTD2XX_NET.cs:2404
void SetAndDisplayPackedData(byte[] Data)
Packs the specified data, sends the data to the controller and displays the data. ...
Class wrapper for FTD2XX.DLL
Definition: FTD2XX_NET.cs:40
This class handles all communication with Direct StripControllers.
FT_STATUS Close()
Closes the handle to an open FTDI device.
Definition: FTD2XX_NET.cs:2512
static void Exception(string Message, Exception E=null)
Writes a exception message to the log.
Definition: Log.cs:144