2 using System.Collections.Generic;
5 using System.Threading;
7 namespace DirectOutput.Cab.Out.FTDIChip
18 private string _SerialNumber =
"";
26 public string SerialNumber
28 get {
return _SerialNumber; }
29 set { _SerialNumber = value; }
38 if (SerialNumber.IsNullOrWhiteSpace())
40 Log.
Exception(
"Could not initialize FT245RBitbangController {0}. SerialNumber has not been set.".Build(Name));
45 Log.
Write(
"FT245RBitbangController {0} with serial number {1} has been initialized and the updater thread has been started.".Build(Name, SerialNumber));
52 public override void Finish()
54 FinishUpdaterThread();
55 Log.
Write(
"FT245RBitbangController {0} with serial number {1} has been finished and the updater thread has been terminated.".Build(Name, SerialNumber));
61 public override void Update()
63 if (NewValue != CurrentValue)
65 UpdaterThreadSignal();
73 private void AddOutputs()
75 for (
int i = 1; i <= 8; i++)
79 Outputs.Add(
new OutputNumbered() { Name =
"{0}.{1:00}".Build(Name, i), Number = i });
101 throw new Exception(
"The OutputValueChanged event handler for the FT245RBitbangController with serial {0} has been called by a sender which is not a OutputNumbered.".Build(SerialNumber));
103 OutputNumbered ON = (OutputNumbered)Output;
105 if (!ON.
Number.IsBetween(1, 64))
107 throw new Exception(
"FT245RBitbangController output numbers must be in the range of 1-8. The supplied output number {0} for FT245RBitbangController with serial number {1} is out of range.".Build(ON.
Number, SerialNumber));
112 lock (ValueChangeLocker)
114 NewValue |= (byte)(1 << (ON.
Number - 1));
119 lock (ValueChangeLocker)
121 NewValue &= (byte)~(1 << (ON.
Number - 1));
129 #region UpdaterThread
134 private void InitUpdaterThread()
137 if (!UpdaterThreadIsActive)
139 KeepUpdaterThreadAlive =
true;
142 UpdaterThread =
new Thread(UpdaterThreadDoIt);
143 UpdaterThread.Name =
"FT245RBitbangController {0} named {1} updater thread ".Build(SerialNumber, Name);
144 UpdaterThread.Start();
148 Log.
Exception(
"FT245RBitbangController {0} named {1} updater thread could not start.".Build(SerialNumber, Name), E);
149 throw new Exception(
"FT245RBitbangController {0} named {1} updater thread could not start.".Build(SerialNumber, Name), E);
158 private void FinishUpdaterThread()
160 if (UpdaterThread != null)
164 KeepUpdaterThreadAlive =
false;
165 lock (UpdaterThreadLocker)
167 Monitor.Pulse(UpdaterThreadLocker);
169 if (!UpdaterThread.Join(1000))
171 UpdaterThread.Abort();
173 UpdaterThread = null;
177 Log.Exception(
"A error occured during termination of FT245RBitbangController ({0}) updater thread.".Build(SerialNumber), E);
178 throw new Exception(
"A error occured during termination of FT245RBitbangController ({0}) updater thread.".Build(SerialNumber, E));
187 public bool UpdaterThreadIsActive
191 if (UpdaterThread != null)
193 if (UpdaterThread.IsAlive)
205 private void UpdaterThreadSignal()
207 lock (UpdaterThreadLocker)
209 Monitor.Pulse(UpdaterThreadLocker);
213 private object ValueChangeLocker =
new object();
214 private byte NewValue = 0;
215 private byte CurrentValue = 255;
218 private Thread UpdaterThread {
get;
set; }
219 private object UpdaterThreadLocker =
new object();
220 private bool KeepUpdaterThreadAlive =
true;
221 private int FirstTryFailCnt = 0;
222 private void UpdaterThreadDoIt()
228 Log.
Warning(
"No connection to FTDI chip {0}. Updater thread will terminate.".Build(SerialNumber));
238 Log.Exception(
"Could not send initial update to FTDI chip {0}. Updater thread will terminate.".Build(SerialNumber));
244 while (KeepUpdaterThreadAlive)
246 lock (ValueChangeLocker)
248 CurrentValue = NewValue;
254 SendUpdate(CurrentValue);
259 if (FirstTryFailCnt < 5)
261 Log.Exception(
"Could not send update to FTDI chip {0} on first try. Will reconnect and send update again.".Build(SerialNumber), E);
263 if (FirstTryFailCnt == 5)
265 Log.Warning(
"Will not log futher warnings on first try failures when sending data to FTDI chip {0}.".Build(SerialNumber));
279 Log.Exception(
"Could not send update to FTDI chip {0}. Tried to reconnect to device but failed. Updater thread will terminate.".Build(SerialNumber), EC);
288 SendUpdate(CurrentValue);
293 Log.Exception(
"Could not send update to FTDI chip {0}. Reconnect to device worked, but sending the update did fail again. Updater thread will terminate.".Build(SerialNumber), EE);
301 Log.Exception(
"Could not send update to FTDI chip {0}. Tried to reconnect to device but failed. Updater thread will terminate.".Build(SerialNumber));
306 if (KeepUpdaterThreadAlive)
308 lock (UpdaterThreadLocker)
310 while (NewValue == CurrentValue && KeepUpdaterThreadAlive)
312 Monitor.Wait(UpdaterThreadLocker, 50);
324 Log.Exception(
"Final update to turn off all output fo FTDI chip {0} failed.".Build(SerialNumber), E);
331 #region FT245R Communication
333 object FTDILocker =
new object();
336 private void Connect()
347 if (SerialNumber.IsNullOrWhiteSpace())
349 Log.Exception(
"The SerialNumber has not been set for the FT245RBitbangController named {0}. Cant connect to device.".Build(Name));
358 FTDI.ErrorHandler(FTDI.OpenBySerialNumber(SerialNumber));
362 Log.Exception(
"Could not open the connection to FTDI chip with serial number {0}.".Build(SerialNumber), E);
370 FTDI.ErrorHandler(FTDI.SetBitMode(0xFF, FTDI.FT_BIT_MODES.FT_BIT_MODE_SYNC_BITBANG));
374 Log.Exception(
"Could set the bitmode to bitbang for FTDI chip with serial number {0}.".Build(SerialNumber), E);
380 Log.Write(
"Connection to FTDI chip {0} established.".Build(SerialNumber));
389 private void SendUpdate(byte OutputData)
396 byte[] Out = { OutputData };
399 FTDI.FT_STATUS Status = FTDI.Write(Out, 1, ref numBytes);
400 if (Status != FTDI.FT_STATUS.FT_OK)
403 FTDI.ErrorHandler(Status);
407 throw new Exception(
"Wrong number of written bytes (expected 1, received {0} was returned when sending data to the FTDI chip {1}".Build(numBytes, SerialNumber));
413 private void Disconnect()
430 FTDI.ErrorHandler(FTDI.Close());
434 Log.Exception(
"A exception occured when closing the FTDI chip {0}.".Build(SerialNumber));
438 Log.Write(
"Connection to FTDI chip {0} closed.".Build(SerialNumber));