Rewritten the T-Balancer code to use the FTDI D2XX drivers directly instead of the System.IO.Ports.SerialPort class. The SerialPort class has some ugly problems like http://connect.microsoft.com/VisualStudio/feedback/details/140018/serialport-crashes-after-disconnect-of-usb-com-port or http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/8a1825d2-c84b-4620-91e7-3934a4d47330 for which no real solution seems to exist. And Microsoft doesn't feel like it needs to be fixed for years now.
authormoel.mich
Mon, 05 Apr 2010 15:31:19 +0000
changeset 87ecdc3bcef083
parent 86 b4f0f206173d
child 88 bce8363c119c
Rewritten the T-Balancer code to use the FTDI D2XX drivers directly instead of the System.IO.Ports.SerialPort class. The SerialPort class has some ugly problems like http://connect.microsoft.com/VisualStudio/feedback/details/140018/serialport-crashes-after-disconnect-of-usb-com-port or http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/8a1825d2-c84b-4620-91e7-3934a4d47330 for which no real solution seems to exist. And Microsoft doesn't feel like it needs to be fixed for years now.
GUI/CrashReportForm.cs
Hardware/TBalancer/FTD2XX.cs
Hardware/TBalancer/TBalancer.cs
Hardware/TBalancer/TBalancerGroup.cs
OpenHardwareMonitor.csproj
Program.cs
     1.1 --- a/GUI/CrashReportForm.cs	Fri Apr 02 16:05:07 2010 +0000
     1.2 +++ b/GUI/CrashReportForm.cs	Mon Apr 05 15:31:19 2010 +0000
     1.3 @@ -74,34 +74,37 @@
     1.4      }
     1.5  
     1.6      private void sendButton_Click(object sender, EventArgs e) {
     1.7 -      Version version = typeof(CrashReportForm).Assembly.GetName().Version;
     1.8 -      WebRequest request = WebRequest.Create(
     1.9 -        "http://openhardwaremonitor.org/report.php");
    1.10 -      request.Method = "POST";
    1.11 -      request.Timeout = 3000;
    1.12 -      request.ContentType = "application/x-www-form-urlencoded";
    1.13 +      try {
    1.14 +        Version version = typeof(CrashReportForm).Assembly.GetName().Version;
    1.15 +        WebRequest request = WebRequest.Create(
    1.16 +          "http://openhardwaremonitor.org/report.php");
    1.17 +        request.Method = "POST";
    1.18 +        request.Timeout = 3000;
    1.19 +        request.ContentType = "application/x-www-form-urlencoded";
    1.20  
    1.21 -      string report = 
    1.22 -        "version=" + HttpUtility.UrlEncode(version.ToString()) + "&" +
    1.23 -        "report=" + HttpUtility.UrlEncode(reportTextBox.Text + 
    1.24 -        commentTextBox.Text);
    1.25 -      byte[] byteArray = Encoding.UTF8.GetBytes(report);          
    1.26 -      request.ContentLength = byteArray.Length;
    1.27 -    
    1.28 -      Stream dataStream = request.GetRequestStream();
    1.29 -      dataStream.Write(byteArray, 0, byteArray.Length);    
    1.30 -      dataStream.Close();
    1.31 -      try {
    1.32 -        WebResponse response = request.GetResponse();
    1.33 -        dataStream = response.GetResponseStream();
    1.34 -        StreamReader reader = new StreamReader(dataStream);
    1.35 -        string responseFromServer = reader.ReadToEnd();
    1.36 -        reader.Close();
    1.37 +        string report =
    1.38 +          "version=" + HttpUtility.UrlEncode(version.ToString()) + "&" +
    1.39 +          "report=" + HttpUtility.UrlEncode(reportTextBox.Text +
    1.40 +          commentTextBox.Text);
    1.41 +        byte[] byteArray = Encoding.UTF8.GetBytes(report);
    1.42 +        request.ContentLength = byteArray.Length;
    1.43 +
    1.44 +        Stream dataStream = request.GetRequestStream();
    1.45 +        dataStream.Write(byteArray, 0, byteArray.Length);
    1.46          dataStream.Close();
    1.47 -        response.Close();
    1.48 -      } catch (WebException) {
    1.49 +        try {
    1.50 +          WebResponse response = request.GetResponse();
    1.51 +          dataStream = response.GetResponseStream();
    1.52 +          StreamReader reader = new StreamReader(dataStream);
    1.53 +          string responseFromServer = reader.ReadToEnd();
    1.54 +          reader.Close();
    1.55 +          dataStream.Close();
    1.56 +          response.Close();
    1.57 +        } catch (WebException) {
    1.58 +        }
    1.59 +      } finally {
    1.60 +        Close();
    1.61        }
    1.62 -      Close();      
    1.63      }
    1.64    }  
    1.65  }
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/Hardware/TBalancer/FTD2XX.cs	Mon Apr 05 15:31:19 2010 +0000
     2.3 @@ -0,0 +1,207 @@
     2.4 +/*
     2.5 +  
     2.6 +  Version: MPL 1.1/GPL 2.0/LGPL 2.1
     2.7 +
     2.8 +  The contents of this file are subject to the Mozilla Public License Version
     2.9 +  1.1 (the "License"); you may not use this file except in compliance with
    2.10 +  the License. You may obtain a copy of the License at
    2.11 + 
    2.12 +  http://www.mozilla.org/MPL/
    2.13 +
    2.14 +  Software distributed under the License is distributed on an "AS IS" basis,
    2.15 +  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
    2.16 +  for the specific language governing rights and limitations under the License.
    2.17 +
    2.18 +  The Original Code is the Open Hardware Monitor code.
    2.19 +
    2.20 +  The Initial Developer of the Original Code is 
    2.21 +  Michael Möller <m.moeller@gmx.ch>.
    2.22 +  Portions created by the Initial Developer are Copyright (C) 2009-2010
    2.23 +  the Initial Developer. All Rights Reserved.
    2.24 +
    2.25 +  Contributor(s):
    2.26 +
    2.27 +  Alternatively, the contents of this file may be used under the terms of
    2.28 +  either the GNU General Public License Version 2 or later (the "GPL"), or
    2.29 +  the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
    2.30 +  in which case the provisions of the GPL or the LGPL are applicable instead
    2.31 +  of those above. If you wish to allow use of your version of this file only
    2.32 +  under the terms of either the GPL or the LGPL, and not to allow others to
    2.33 +  use your version of this file under the terms of the MPL, indicate your
    2.34 +  decision by deleting the provisions above and replace them with the notice
    2.35 +  and other provisions required by the GPL or the LGPL. If you do not delete
    2.36 +  the provisions above, a recipient may use your version of this file under
    2.37 +  the terms of any one of the MPL, the GPL or the LGPL.
    2.38 + 
    2.39 +*/
    2.40 +
    2.41 +using System;
    2.42 +using System.Collections.Generic;
    2.43 +using System.Runtime.InteropServices;
    2.44 +
    2.45 +namespace OpenHardwareMonitor.Hardware.TBalancer {
    2.46 +
    2.47 +  public enum FT_DEVICE : uint {
    2.48 +    FT_DEVICE_BM,
    2.49 +    FT_DEVICE_AM,
    2.50 +    FT_DEVICE_100AX,
    2.51 +    FT_DEVICE_UNKNOWN,
    2.52 +    FT_DEVICE_2232,
    2.53 +    FT_DEVICE_232R,
    2.54 +    FT_DEVICE_2232H,
    2.55 +    FT_DEVICE_4232H
    2.56 +  }
    2.57 +
    2.58 +  public enum FT_STATUS {
    2.59 +    FT_OK,
    2.60 +    FT_INVALID_HANDLE,
    2.61 +    FT_DEVICE_NOT_FOUND,
    2.62 +    FT_DEVICE_NOT_OPENED,
    2.63 +    FT_IO_ERROR,
    2.64 +    FT_INSUFFICIENT_RESOURCES,
    2.65 +    FT_INVALID_PARAMETER,
    2.66 +    FT_INVALID_BAUD_RATE,
    2.67 +    FT_DEVICE_NOT_OPENED_FOR_ERASE,
    2.68 +    FT_DEVICE_NOT_OPENED_FOR_WRITE,
    2.69 +    FT_FAILED_TO_WRITE_DEVICE,
    2.70 +    FT_EEPROM_READ_FAILED,
    2.71 +    FT_EEPROM_WRITE_FAILED,
    2.72 +    FT_EEPROM_ERASE_FAILED,
    2.73 +    FT_EEPROM_NOT_PRESENT,
    2.74 +    FT_EEPROM_NOT_PROGRAMMED,
    2.75 +    FT_INVALID_ARGS,
    2.76 +    FT_OTHER_ERROR
    2.77 +  }
    2.78 +
    2.79 +  public enum FT_FLOW_CONTROL : ushort {
    2.80 +    FT_FLOW_DTR_DSR = 512,
    2.81 +    FT_FLOW_NONE = 0,
    2.82 +    FT_FLOW_RTS_CTS = 256,
    2.83 +    FT_FLOW_XON_XOFF = 1024,
    2.84 +  }
    2.85 +
    2.86 +  public enum FT_PURGE : uint {
    2.87 +    FT_PURGE_RX = 1,
    2.88 +    FT_PURGE_TX = 2,
    2.89 +    FT_PURGE_ALL = 3,
    2.90 +  }
    2.91 +
    2.92 +  [StructLayout(LayoutKind.Sequential)]
    2.93 +  public struct FT_HANDLE {
    2.94 +    private uint handle;
    2.95 +  }
    2.96 +
    2.97 +  [StructLayout(LayoutKind.Sequential)]
    2.98 +  public struct FT_DEVICE_INFO_NODE {    
    2.99 +    public uint Flags;
   2.100 +    public FT_DEVICE Type; 
   2.101 +    public uint ID; 
   2.102 +    public uint LocId; 
   2.103 +    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
   2.104 +    public string SerialNumber; 
   2.105 +    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
   2.106 +    public string Description;
   2.107 +    public FT_HANDLE Handle;
   2.108 +  }
   2.109 +
   2.110 +  public class FTD2XX {
   2.111 +
   2.112 +    public delegate FT_STATUS FT_CreateDeviceInfoListDelegate(
   2.113 +      out uint numDevices);
   2.114 +    public delegate FT_STATUS FT_GetDeviceInfoListDelegate(
   2.115 +      [Out] FT_DEVICE_INFO_NODE[] deviceInfoNodes, ref uint length);
   2.116 +    public delegate FT_STATUS FT_OpenDelegate(int device, out FT_HANDLE handle);
   2.117 +    public delegate FT_STATUS FT_CloseDelegate(FT_HANDLE handle);
   2.118 +    public delegate FT_STATUS FT_SetBaudRateDelegate(FT_HANDLE handle,
   2.119 +      uint baudRate);
   2.120 +    public delegate FT_STATUS FT_SetDataCharacteristicsDelegate(
   2.121 +      FT_HANDLE handle, byte wordLength, byte stopBits, byte parity);
   2.122 +    public delegate FT_STATUS FT_SetFlowControlDelegate(FT_HANDLE handle,
   2.123 +      FT_FLOW_CONTROL flowControl, byte xon, byte xoff);
   2.124 +    public delegate FT_STATUS FT_SetTimeoutsDelegate(FT_HANDLE handle,
   2.125 +      uint readTimeout, uint writeTimeout);
   2.126 +    public delegate FT_STATUS FT_WriteDelegate(FT_HANDLE handle, byte[] buffer,
   2.127 +      uint bytesToWrite, out uint bytesWritten);
   2.128 +    public delegate FT_STATUS FT_PurgeDelegate(FT_HANDLE handle, FT_PURGE mask);
   2.129 +    public delegate FT_STATUS FT_GetStatusDelegate(FT_HANDLE handle,
   2.130 +      out uint amountInRxQueue, out uint amountInTxQueue, out uint eventStatus);
   2.131 +    public delegate FT_STATUS FT_ReadDelegate(FT_HANDLE handle, 
   2.132 +      [Out] byte[] buffer, uint bytesToRead, out uint bytesReturned);
   2.133 +
   2.134 +    public static FT_CreateDeviceInfoListDelegate FT_CreateDeviceInfoList;
   2.135 +    public static FT_GetDeviceInfoListDelegate FT_GetDeviceInfoList;
   2.136 +    public static FT_OpenDelegate FT_Open;
   2.137 +    public static FT_CloseDelegate FT_Close;
   2.138 +    public static FT_SetBaudRateDelegate FT_SetBaudRate;
   2.139 +    public static FT_SetDataCharacteristicsDelegate FT_SetDataCharacteristics;
   2.140 +    public static FT_SetFlowControlDelegate FT_SetFlowControl;
   2.141 +    public static FT_SetTimeoutsDelegate FT_SetTimeouts;
   2.142 +    public static FT_WriteDelegate FT_Write;
   2.143 +    public static FT_PurgeDelegate FT_Purge;
   2.144 +    public static FT_GetStatusDelegate FT_GetStatus;
   2.145 +    public static FT_ReadDelegate FT_Read;
   2.146 +
   2.147 +    public static FT_STATUS Write(FT_HANDLE handle, byte[] buffer) {
   2.148 +      uint bytesWritten;
   2.149 +      FT_STATUS status = FT_Write(handle, buffer, (uint)buffer.Length, 
   2.150 +        out bytesWritten);
   2.151 +      if (bytesWritten != buffer.Length)
   2.152 +        return FT_STATUS.FT_FAILED_TO_WRITE_DEVICE;
   2.153 +      else
   2.154 +        return status;
   2.155 +    }
   2.156 +
   2.157 +    public static int BytesToRead(FT_HANDLE handle) {
   2.158 +      uint amountInRxQueue;
   2.159 +      uint amountInTxQueue;
   2.160 +      uint eventStatus;
   2.161 +      if (FT_GetStatus(handle, out amountInRxQueue, out amountInTxQueue,
   2.162 +        out eventStatus) == FT_STATUS.FT_OK) {
   2.163 +        return (int)amountInRxQueue;
   2.164 +      } else {
   2.165 +        return 0;
   2.166 +      }
   2.167 +    }
   2.168 +
   2.169 +    public static byte ReadByte(FT_HANDLE handle) {
   2.170 +      byte[] buffer = new byte[1];
   2.171 +      uint bytesReturned;
   2.172 +      FT_STATUS status = FT_Read(handle, buffer, 1, out bytesReturned);
   2.173 +      if (status != FT_STATUS.FT_OK || bytesReturned != 1)
   2.174 +        throw new Exception();
   2.175 +      return buffer[0];
   2.176 +    }
   2.177 +
   2.178 +    private static string dllName;
   2.179 +
   2.180 +    private static void GetDelegate<T>(string entryPoint, out T newDelegate)
   2.181 +      where T : class {
   2.182 +      DllImportAttribute attribute = new DllImportAttribute(dllName);
   2.183 +      attribute.CallingConvention = CallingConvention.StdCall;
   2.184 +      attribute.PreserveSig = true;
   2.185 +      attribute.EntryPoint = entryPoint;
   2.186 +      PInvokeDelegateFactory.CreateDelegate(attribute, out newDelegate);
   2.187 +    }
   2.188 +
   2.189 +    static FTD2XX() {
   2.190 +      int p = (int)System.Environment.OSVersion.Platform;
   2.191 +      if ((p == 4) || (p == 128))
   2.192 +        dllName = "libftd2xx.so";
   2.193 +      else
   2.194 +        dllName = "ftd2xx.dll";
   2.195 +
   2.196 +      GetDelegate("FT_CreateDeviceInfoList", out FT_CreateDeviceInfoList);
   2.197 +      GetDelegate("FT_GetDeviceInfoList", out FT_GetDeviceInfoList);
   2.198 +      GetDelegate("FT_Open", out FT_Open);
   2.199 +      GetDelegate("FT_Close", out FT_Close);
   2.200 +      GetDelegate("FT_SetBaudRate", out FT_SetBaudRate);
   2.201 +      GetDelegate("FT_SetDataCharacteristics", out FT_SetDataCharacteristics);
   2.202 +      GetDelegate("FT_SetFlowControl", out FT_SetFlowControl);
   2.203 +      GetDelegate("FT_SetTimeouts", out FT_SetTimeouts);
   2.204 +      GetDelegate("FT_Write", out FT_Write);
   2.205 +      GetDelegate("FT_Purge", out FT_Purge);
   2.206 +      GetDelegate("FT_GetStatus", out FT_GetStatus);
   2.207 +      GetDelegate("FT_Read", out FT_Read);
   2.208 +    }
   2.209 +  }
   2.210 +}
     3.1 --- a/Hardware/TBalancer/TBalancer.cs	Fri Apr 02 16:05:07 2010 +0000
     3.2 +++ b/Hardware/TBalancer/TBalancer.cs	Mon Apr 05 15:31:19 2010 +0000
     3.3 @@ -39,16 +39,14 @@
     3.4  using System.Collections.Generic;
     3.5  using System.Configuration;
     3.6  using System.Drawing;
     3.7 -using System.IO;
     3.8 -using System.IO.Ports;
     3.9  using System.Text;
    3.10  
    3.11  namespace OpenHardwareMonitor.Hardware.TBalancer {
    3.12    public class TBalancer : IHardware {
    3.13  
    3.14 -    private string portName;
    3.15 +    private int portIndex;
    3.16 +    private FT_HANDLE handle;
    3.17      private Image icon;
    3.18 -    private SerialPort serialPort;
    3.19      private byte protocolVersion;
    3.20      private Sensor[] digitalTemperatures = new Sensor[8];
    3.21      private Sensor[] analogTemperatures = new Sensor[4];
    3.22 @@ -68,8 +66,8 @@
    3.23      private delegate void MethodDelegate();
    3.24      private MethodDelegate alternativeRequest;    
    3.25  
    3.26 -    public TBalancer(string portName, byte protocolVersion) {
    3.27 -      this.portName = portName;
    3.28 +    public TBalancer(int portIndex, byte protocolVersion) {
    3.29 +      this.portIndex = portIndex;
    3.30        this.icon = Utilities.EmbeddedResources.GetImage("bigng.png");
    3.31        this.protocolVersion = protocolVersion;
    3.32  
    3.33 @@ -108,12 +106,8 @@
    3.34  
    3.35        alternativeRequest = new MethodDelegate(DelayedAlternativeRequest);
    3.36  
    3.37 -      try {
    3.38 -        serialPort = new SerialPort(portName, 19200, Parity.None, 8,
    3.39 -          StopBits.One);
    3.40 -        serialPort.Open();
    3.41 -        Update();
    3.42 -      } catch (IOException) { }      
    3.43 +      Open();
    3.44 +      Update(); 
    3.45      }
    3.46  
    3.47      private void ActivateSensor(Sensor sensor) {
    3.48 @@ -171,10 +165,10 @@
    3.49      private void ReadData() {
    3.50        int[] data = new int[285];
    3.51        for (int i = 0; i < data.Length; i++)
    3.52 -        data[i] = serialPort.ReadByte();
    3.53 +        data[i] = FTD2XX.ReadByte(handle);
    3.54  
    3.55        if (data[0] != STARTFLAG) {
    3.56 -        serialPort.DiscardInBuffer();   
    3.57 +        FTD2XX.FT_Purge(handle, FT_PURGE.FT_PURGE_RX);   
    3.58          return;
    3.59        }
    3.60  
    3.61 @@ -258,8 +252,7 @@
    3.62      }
    3.63  
    3.64      public string Identifier {
    3.65 -      get { return "/bigng/" + 
    3.66 -        this.portName.TrimStart(new char[]{'/'}).ToLower(); }
    3.67 +      get { return "/bigng/" + this.portIndex; }
    3.68      }
    3.69  
    3.70      public IHardware[] SubHardware {
    3.71 @@ -275,7 +268,7 @@
    3.72  
    3.73        r.AppendLine("T-Balancer bigNG");
    3.74        r.AppendLine();
    3.75 -      r.Append("Port Name: "); r.AppendLine(serialPort.PortName);
    3.76 +      r.Append("Port Index: "); r.AppendLine(portIndex.ToString());
    3.77        r.AppendLine();
    3.78  
    3.79        r.AppendLine("Primary System Information Answer");
    3.80 @@ -318,31 +311,32 @@
    3.81      }
    3.82  
    3.83      private void DelayedAlternativeRequest() {
    3.84 -      System.Threading.Thread.Sleep(500);
    3.85 -      try {
    3.86 -        if (serialPort.IsOpen)
    3.87 -          serialPort.Write(new byte[] { 0x37 }, 0, 1);
    3.88 -      } catch (Exception) { }
    3.89 +      System.Threading.Thread.Sleep(500);      
    3.90 +      FTD2XX.Write(handle, new byte[] { 0x37 });
    3.91      }
    3.92  
    3.93 -    public void Update() {      
    3.94 -      try {
    3.95 -        while (serialPort.IsOpen && serialPort.BytesToRead >= 285)
    3.96 -          ReadData();
    3.97 -        if (serialPort.BytesToRead == 1)
    3.98 -          serialPort.ReadByte();
    3.99 +    public void Open() {
   3.100 +      FTD2XX.FT_Open(portIndex, out handle); 
   3.101 +      FTD2XX.FT_SetBaudRate(handle, 19200);
   3.102 +      FTD2XX.FT_SetDataCharacteristics(handle, 8, 1, 0);
   3.103 +      FTD2XX.FT_SetFlowControl(handle, FT_FLOW_CONTROL.FT_FLOW_RTS_CTS, 0x11,
   3.104 +        0x13);
   3.105 +      FTD2XX.FT_SetTimeouts(handle, 1000, 1000);
   3.106 +      FTD2XX.FT_Purge(handle, FT_PURGE.FT_PURGE_ALL);
   3.107 +    }
   3.108  
   3.109 -        serialPort.Write(new byte[] { 0x38 }, 0, 1);
   3.110 -        alternativeRequest.BeginInvoke(null, null);
   3.111 -      } catch (InvalidOperationException) {
   3.112 -        foreach (Sensor sensor in active)
   3.113 -          sensor.Value = null;
   3.114 -      }      
   3.115 +    public void Update() {
   3.116 +      while (FTD2XX.BytesToRead(handle) >= 285)
   3.117 +        ReadData();
   3.118 +      if (FTD2XX.BytesToRead(handle) == 1)
   3.119 +        FTD2XX.ReadByte(handle);
   3.120 +
   3.121 +      FTD2XX.Write(handle, new byte[] { 0x38 });
   3.122 +      alternativeRequest.BeginInvoke(null, null);
   3.123      }
   3.124  
   3.125      public void Close() {
   3.126 -      if (serialPort.IsOpen)
   3.127 -        serialPort.Close();
   3.128 +      FTD2XX.FT_Close(handle);
   3.129      }
   3.130  
   3.131      public event SensorEventHandler SensorAdded;
     4.1 --- a/Hardware/TBalancer/TBalancerGroup.cs	Fri Apr 02 16:05:07 2010 +0000
     4.2 +++ b/Hardware/TBalancer/TBalancerGroup.cs	Mon Apr 05 15:31:19 2010 +0000
     4.3 @@ -49,79 +49,87 @@
     4.4      private StringBuilder report = new StringBuilder();
     4.5  
     4.6      public TBalancerGroup() {
     4.7 -   
     4.8 -      string[] portNames = SerialPort.GetPortNames();      
     4.9 -      for (int i = portNames.Length - 1; i >= 0; i--) {
    4.10 -        try {
    4.11  
    4.12 -          SerialPort serialPort =
    4.13 -            new SerialPort(portNames[i], 19200, Parity.None, 8, StopBits.One);
    4.14 -          
    4.15 -          bool isValid = false;
    4.16 -          byte protocolVersion = 0;
    4.17 -          report.Append("Port Name: "); report.AppendLine(portNames[i]);
    4.18 +      uint numDevices;
    4.19 +      try {
    4.20 +        FTD2XX.FT_CreateDeviceInfoList(out numDevices);
    4.21 +      } catch (DllNotFoundException) { return; } 
    4.22 +        catch (ArgumentNullException) { return; }
    4.23 +     
    4.24 +      FT_DEVICE_INFO_NODE[] info = new FT_DEVICE_INFO_NODE[numDevices];
    4.25 +      FTD2XX.FT_GetDeviceInfoList(info, ref numDevices);
    4.26  
    4.27 -          try {
    4.28 -            serialPort.Open();
    4.29 -          } catch (UnauthorizedAccessException) {
    4.30 -            report.AppendLine("Exception: Access Denied");
    4.31 -          }
    4.32 -       
    4.33 -          if (serialPort.IsOpen) {
    4.34 -            if (serialPort.CtsHolding) {
    4.35 -              serialPort.DiscardInBuffer();
    4.36 -              serialPort.DiscardOutBuffer();
    4.37 -              serialPort.Write(new byte[] { 0x38 }, 0, 1);
    4.38 -              int j = 0;
    4.39 -              while (serialPort.BytesToRead == 0 && j < 2) {
    4.40 -                Thread.Sleep(100);
    4.41 -                j++;
    4.42 -              }
    4.43 -              if (serialPort.BytesToRead > 0) {
    4.44 -                if (serialPort.ReadByte() == TBalancer.STARTFLAG) {
    4.45 -                  while (serialPort.BytesToRead < 284 && j < 5) {
    4.46 -                    Thread.Sleep(100);
    4.47 -                    j++;
    4.48 -                  }
    4.49 -                  int length = serialPort.BytesToRead;
    4.50 -                  if (length >= 284) {
    4.51 -                    byte[] data = new byte[285];
    4.52 -                    data[0] = TBalancer.STARTFLAG;
    4.53 -                    for (int k = 1; k < data.Length; k++)
    4.54 -                      data[k] = (byte)serialPort.ReadByte();
    4.55 +      for (int i = 0; i < numDevices; i++) {
    4.56 +        report.Append("Device Index: "); report.AppendLine(i.ToString());
    4.57 +        
    4.58 +        FT_HANDLE handle;
    4.59 +        FT_STATUS status;
    4.60 +        status = FTD2XX.FT_Open(i, out handle);
    4.61 +        if (status != FT_STATUS.FT_OK) {
    4.62 +          report.AppendLine("Open Status: " + status);
    4.63 +          continue;
    4.64 +        }
    4.65  
    4.66 -                    // check protocol version 2X (protocols seen: 2C, 2A, 28)
    4.67 -                    isValid = (data[274] & 0xF0) == 0x20;
    4.68 -                    protocolVersion = data[274];
    4.69 -                    if (!isValid) {
    4.70 -                      report.Append("Status: Wrong Protocol Version: 0x");
    4.71 -                      report.AppendLine(protocolVersion.ToString("X"));
    4.72 -                    }
    4.73 -                  } else {
    4.74 -                    report.AppendLine("Status: Wrong Message Length: " +length);
    4.75 -                  }
    4.76 -                } else {
    4.77 -                  report.AppendLine("Status: Wrong Startflag");
    4.78 -                }
    4.79 -              } else {
    4.80 -                report.AppendLine("Status: No Response");
    4.81 +        FTD2XX.FT_SetBaudRate(handle, 19200);
    4.82 +        FTD2XX.FT_SetDataCharacteristics(handle, 8, 1, 0);
    4.83 +        FTD2XX.FT_SetFlowControl(handle, FT_FLOW_CONTROL.FT_FLOW_RTS_CTS, 0x11, 
    4.84 +          0x13);
    4.85 +        FTD2XX.FT_SetTimeouts(handle, 1000, 1000);
    4.86 +        FTD2XX.FT_Purge(handle, FT_PURGE.FT_PURGE_ALL);
    4.87 +        
    4.88 +        status = FTD2XX.Write(handle, new byte[] { 0x38 });
    4.89 +        if (status != FT_STATUS.FT_OK) {
    4.90 +          report.AppendLine("Write Status: " + status);
    4.91 +          FTD2XX.FT_Close(handle);
    4.92 +          continue;
    4.93 +        }
    4.94 +
    4.95 +        bool isValid = false;
    4.96 +        byte protocolVersion = 0;
    4.97 +
    4.98 +        int j = 0;
    4.99 +        while (FTD2XX.BytesToRead(handle) == 0 && j < 2) {
   4.100 +          Thread.Sleep(100);
   4.101 +          j++;
   4.102 +        }
   4.103 +        if (FTD2XX.BytesToRead(handle) > 0) {
   4.104 +          if (FTD2XX.ReadByte(handle) == TBalancer.STARTFLAG) {
   4.105 +            while (FTD2XX.BytesToRead(handle) < 284 && j < 5) {
   4.106 +              Thread.Sleep(100);
   4.107 +              j++;
   4.108 +            }
   4.109 +            int length = FTD2XX.BytesToRead(handle);
   4.110 +            if (length >= 284) {
   4.111 +              byte[] data = new byte[285];
   4.112 +              data[0] = TBalancer.STARTFLAG;
   4.113 +              for (int k = 1; k < data.Length; k++)
   4.114 +                data[k] = FTD2XX.ReadByte(handle);
   4.115 +
   4.116 +              // check protocol version 2X (protocols seen: 2C, 2A, 28)
   4.117 +              isValid = (data[274] & 0xF0) == 0x20;
   4.118 +              protocolVersion = data[274];
   4.119 +              if (!isValid) {
   4.120 +                report.Append("Status: Wrong Protocol Version: 0x");
   4.121 +                report.AppendLine(protocolVersion.ToString("X"));
   4.122                }
   4.123              } else {
   4.124 -              report.AppendLine("Status: Not Clear to Send");
   4.125 +              report.AppendLine("Status: Wrong Message Length: " + length);
   4.126              }
   4.127 -            serialPort.DiscardInBuffer();
   4.128 -            serialPort.Close();
   4.129 -          } else {            
   4.130 -            report.AppendLine("Status: Port not Open");
   4.131 -          }                          
   4.132 -          if (isValid) {
   4.133 -            report.AppendLine("Status: OK");
   4.134 -            hardware.Add(new TBalancer(portNames[i], protocolVersion));
   4.135 -            return;
   4.136 +          } else {
   4.137 +            report.AppendLine("Status: Wrong Startflag");
   4.138            }
   4.139 -        } catch (Exception e) {
   4.140 -          report.AppendLine(e.ToString());
   4.141 -        } 
   4.142 +        } else {
   4.143 +          report.AppendLine("Status: No Response");
   4.144 +        }
   4.145 +
   4.146 +        FTD2XX.FT_Purge(handle, FT_PURGE.FT_PURGE_ALL);
   4.147 +        FTD2XX.FT_Close(handle);
   4.148 +
   4.149 +        if (isValid) {
   4.150 +          report.AppendLine("Status: OK");
   4.151 +          hardware.Add(new TBalancer(i, protocolVersion));
   4.152 +          return;
   4.153 +        }
   4.154          report.AppendLine();
   4.155        }
   4.156      }
   4.157 @@ -134,7 +142,7 @@
   4.158  
   4.159      public string GetReport() {
   4.160        if (report.Length > 0) {
   4.161 -        report.Insert(0, "Serial Port T-Balancer" + Environment.NewLine +
   4.162 +        report.Insert(0, "FTD2XX" + Environment.NewLine +
   4.163            Environment.NewLine);
   4.164          report.AppendLine();
   4.165          return report.ToString();
     5.1 --- a/OpenHardwareMonitor.csproj	Fri Apr 02 16:05:07 2010 +0000
     5.2 +++ b/OpenHardwareMonitor.csproj	Mon Apr 05 15:31:19 2010 +0000
     5.3 @@ -95,6 +95,7 @@
     5.4      <Compile Include="Hardware\Mainboard\SMBIOS.cs" />
     5.5      <Compile Include="Hardware\LPC\W836XX.cs" />
     5.6      <Compile Include="Hardware\Computer.cs" />
     5.7 +    <Compile Include="Hardware\TBalancer\FTD2XX.cs" />
     5.8      <Compile Include="Properties\AssemblyInfo.cs" />
     5.9      <Compile Include="GUI\AboutBox.cs">
    5.10        <SubType>Form</SubType>
     6.1 --- a/Program.cs	Fri Apr 02 16:05:07 2010 +0000
     6.2 +++ b/Program.cs	Mon Apr 05 15:31:19 2010 +0000
     6.3 @@ -48,6 +48,11 @@
     6.4      [STAThread]
     6.5      public static void Main() {
     6.6        #if !DEBUG
     6.7 +        Application.ThreadException += 
     6.8 +          new ThreadExceptionEventHandler(Application_ThreadException);
     6.9 +        Application.SetUnhandledExceptionMode(
    6.10 +          UnhandledExceptionMode.CatchException);
    6.11 +
    6.12          AppDomain.CurrentDomain.UnhandledException += 
    6.13            new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
    6.14        #endif
    6.15 @@ -62,13 +67,31 @@
    6.16        }
    6.17      }
    6.18  
    6.19 +    private static void ReportException(Exception e) {
    6.20 +      CrashReportForm form = new CrashReportForm();
    6.21 +      form.Exception = e;
    6.22 +      form.ShowDialog();
    6.23 +    }
    6.24 +
    6.25 +    public static void Application_ThreadException(object sender, 
    6.26 +      ThreadExceptionEventArgs e) 
    6.27 +    {
    6.28 +      try {
    6.29 +        ReportException(e.Exception);
    6.30 +      } catch {
    6.31 +      } finally {
    6.32 +        Application.Exit();
    6.33 +      }
    6.34 +    }
    6.35 +
    6.36      public static void CurrentDomain_UnhandledException(object sender, 
    6.37        UnhandledExceptionEventArgs args) 
    6.38      {
    6.39 -      CrashReportForm form = new CrashReportForm();
    6.40 -      form.Exception = (Exception)args.ExceptionObject;
    6.41 -      form.ShowDialog();
    6.42 -      Environment.Exit(0);
    6.43 +      try {
    6.44 +        Exception e = args.ExceptionObject as Exception;
    6.45 +        if (e != null)
    6.46 +          ReportException(e);
    6.47 +      } catch { } 
    6.48      }   
    6.49    }
    6.50  }