first commit

This commit is contained in:
Wesley Hofman
2025-09-18 14:23:18 +02:00
commit 2f1f4199ad
293 changed files with 54467 additions and 0 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,55 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.50727</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{2256AEA0-6A5A-4506-9F4B-99AB11C0ECA0}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>EEPROM</RootNamespace>
<AssemblyName>EEPROM</AssemblyName>
<SccProjectName>SAK</SccProjectName>
<SccLocalPath>SAK</SccLocalPath>
<SccAuxPath>SAK</SccAuxPath>
<SccProvider>SAK</SccProvider>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="FTD2XX_NET, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\Utils\FTD2XX_NET\FTD2XX_NET\FTD2XX_NET\bin\Release\FTD2XX_NET.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -0,0 +1,341 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using FTD2XX_NET;
namespace EEPROM
{
class Program
{
static void Main(string[] args)
{
UInt32 ftdiDeviceCount = 0;
FTDI.FT_STATUS ftStatus = FTDI.FT_STATUS.FT_OK;
// Create new instance of the FTDI device class
FTDI myFtdiDevice = new FTDI();
// Determine the number of FTDI devices connected to the machine
ftStatus = myFtdiDevice.GetNumberOfDevices(ref ftdiDeviceCount);
// Check status
if (ftStatus == FTDI.FT_STATUS.FT_OK)
{
Console.WriteLine("Number of FTDI devices: " + ftdiDeviceCount.ToString());
Console.WriteLine("");
}
else
{
// Wait for a key press
Console.WriteLine("Failed to get number of devices (error " + ftStatus.ToString() + ")");
Console.ReadKey();
return;
}
// If no devices available, return
if (ftdiDeviceCount == 0)
{
// Wait for a key press
Console.WriteLine("Failed to get number of devices (error " + ftStatus.ToString() + ")");
Console.ReadKey();
return;
}
// Allocate storage for device info list
FTDI.FT_DEVICE_INFO_NODE[] ftdiDeviceList = new FTDI.FT_DEVICE_INFO_NODE[ftdiDeviceCount];
// Populate our device list
ftStatus = myFtdiDevice.GetDeviceList(ftdiDeviceList);
if (ftStatus == FTDI.FT_STATUS.FT_OK)
{
for (UInt32 i = 0; i < ftdiDeviceCount; i++)
{
Console.WriteLine("Device Index: " + i.ToString());
Console.WriteLine("Flags: " + String.Format("{0:x}", ftdiDeviceList[i].Flags));
Console.WriteLine("Type: " + ftdiDeviceList[i].Type.ToString());
Console.WriteLine("ID: " + String.Format("{0:x}", ftdiDeviceList[i].ID));
Console.WriteLine("Location ID: " + String.Format("{0:x}", ftdiDeviceList[i].LocId));
Console.WriteLine("Serial Number: " + ftdiDeviceList[i].SerialNumber.ToString());
Console.WriteLine("Description: " + ftdiDeviceList[i].Description.ToString());
Console.WriteLine("");
}
}
// Open first device in our list by serial number
ftStatus = myFtdiDevice.OpenBySerialNumber(ftdiDeviceList[0].SerialNumber);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
// Wait for a key press
Console.WriteLine("Failed to open device (error " + ftStatus.ToString() + ")");
Console.ReadKey();
return;
}
// Create our device EEPROM structure based on the type of device we have open
if (ftdiDeviceList[0].Type == FTDI.FT_DEVICE.FT_DEVICE_232R)
{
// We have an FT232R or FT245R so use FT232R EEPROM structure
FTDI.FT232R_EEPROM_STRUCTURE myEEData = new FTDI.FT232R_EEPROM_STRUCTURE();
// Read the device EEPROM
// This can throw an exception if trying to read a device type that does not
// match the EEPROM structure being used, so should always use a
// try - catch block when calling
try
{
ftStatus = myFtdiDevice.ReadFT232REEPROM(myEEData);
}
catch (FTDI.FT_EXCEPTION)
{
Console.WriteLine("Exception thrown when calling ReadFT232REEPROM");
}
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
// Wait for a key press
Console.WriteLine("Failed to read device EEPROM (error " + ftStatus.ToString() + ")");
Console.ReadKey();
// Close the device
myFtdiDevice.Close();
return;
}
// Write common EEPROM elements to our console
Console.WriteLine("EEPROM Contents for device at index 0:");
Console.WriteLine("Vendor ID: " + String.Format("{0:x}", myEEData.VendorID));
Console.WriteLine("Product ID: " + String.Format("{0:x}", myEEData.ProductID));
Console.WriteLine("Manufacturer: " + myEEData.Manufacturer.ToString());
Console.WriteLine("Manufacturer ID: " + myEEData.ManufacturerID.ToString());
Console.WriteLine("Description: " + myEEData.Description.ToString());
Console.WriteLine("Serial Number: " + myEEData.SerialNumber.ToString());
Console.WriteLine("Max Power: " + myEEData.MaxPower.ToString() + "mA");
Console.WriteLine("Self Powered: " + myEEData.SelfPowered.ToString());
Console.WriteLine("Remote Wakeup Enabled: " + myEEData.RemoteWakeup.ToString());
Console.WriteLine("");
// Change our serial number to write back to device
// By setting to an empty string, we allow the FTD2XX DLL
// to generate a serial number
myEEData.SerialNumber = String.Empty;
// Write our modified data structure back to the device EEPROM
// This can throw an exception if trying to write a device type that does not
// match the EEPROM structure being used, so should always use a
// try - catch block when calling
try
{
ftStatus = myFtdiDevice.WriteFT232REEPROM(myEEData);
}
catch (FTDI.FT_EXCEPTION)
{
Console.WriteLine("Exception thrown when calling WriteFT232REEPROM");
}
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
// Wait for a key press
Console.WriteLine("Failed to write device EEPROM (error " + ftStatus.ToString() + ")");
Console.ReadKey();
// Close the device
myFtdiDevice.Close();
return;
}
}
else if (ftdiDeviceList[0].Type == FTDI.FT_DEVICE.FT_DEVICE_2232)
{
// We have an FT2232 so use FT2232 EEPROM structure
FTDI.FT2232_EEPROM_STRUCTURE myEEData = new FTDI.FT2232_EEPROM_STRUCTURE();
// Read the device EEPROM
ftStatus = myFtdiDevice.ReadFT2232EEPROM(myEEData);
// This can throw an exception if trying to read a device type that does not
// match the EEPROM structure being used, so should always use a
// try - catch block when calling
try
{
ftStatus = myFtdiDevice.ReadFT2232EEPROM(myEEData);
}
catch (FTDI.FT_EXCEPTION)
{
Console.WriteLine("Exception thrown when calling ReadFT2232EEPROM");
}
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
// Wait for a key press
Console.WriteLine("Failed to read device EEPROM (error " + ftStatus.ToString() + ")");
Console.ReadKey();
// Close the device
myFtdiDevice.Close();
return;
}
// Write common EEPROM elements to our console
Console.WriteLine("EEPROM Contents for device at index 0:");
Console.WriteLine("Vendor ID: " + String.Format("{0:x}", myEEData.VendorID));
Console.WriteLine("Product ID: " + String.Format("{0:x}", myEEData.ProductID));
Console.WriteLine("Manufacturer: " + myEEData.Manufacturer.ToString());
Console.WriteLine("Manufacturer ID: " + myEEData.ManufacturerID.ToString());
Console.WriteLine("Description: " + myEEData.Description.ToString());
Console.WriteLine("Serial Number: " + myEEData.SerialNumber.ToString());
Console.WriteLine("Max Power: " + myEEData.MaxPower.ToString() + "mA");
Console.WriteLine("Self Powered: " + myEEData.SelfPowered.ToString());
Console.WriteLine("Remote Wakeup Enabled: " + myEEData.RemoteWakeup.ToString());
Console.WriteLine("");
// Change our serial number to write back to device
// By setting to an empty string, we allow the FTD2XX DLL
// to generate a serial number
myEEData.SerialNumber = String.Empty;
// Write our modified data structure back to the device EEPROM
// This can throw an exception if trying to write a device type that does not
// match the EEPROM structure being used, so should always use a
// try - catch block when calling
try
{
ftStatus = myFtdiDevice.WriteFT2232EEPROM(myEEData);
}
catch (FTDI.FT_EXCEPTION)
{
Console.WriteLine("Exception thrown when calling WriteFT2232EEPROM");
}
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
// Wait for a key press
Console.WriteLine("Failed to write device EEPROM (error " + ftStatus.ToString() + ")");
Console.ReadKey();
// Close the device
myFtdiDevice.Close();
return;
}
}
else if (ftdiDeviceList[0].Type == FTDI.FT_DEVICE.FT_DEVICE_BM)
{
// We have an FT232B or FT245B so use FT232B EEPROM structure
FTDI.FT232B_EEPROM_STRUCTURE myEEData = new FTDI.FT232B_EEPROM_STRUCTURE();
// Read the device EEPROM
ftStatus = myFtdiDevice.ReadFT232BEEPROM(myEEData);
// This can throw an exception if trying to read a device type that does not
// match the EEPROM structure being used, so should always use a
// try - catch block when calling
try
{
ftStatus = myFtdiDevice.ReadFT232BEEPROM(myEEData);
}
catch (FTDI.FT_EXCEPTION)
{
Console.WriteLine("Exception thrown when calling ReadFT232BEEPROM");
}
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
// Wait for a key press
Console.WriteLine("Failed to read device EEPROM (error " + ftStatus.ToString() + ")");
Console.ReadKey();
// Close the device
myFtdiDevice.Close();
return;
}
// Write common EEPROM elements to our console
Console.WriteLine("EEPROM Contents for device at index 0:");
Console.WriteLine("Vendor ID: " + String.Format("{0:x}", myEEData.VendorID));
Console.WriteLine("Product ID: " + String.Format("{0:x}", myEEData.ProductID));
Console.WriteLine("Manufacturer: " + myEEData.Manufacturer.ToString());
Console.WriteLine("Manufacturer ID: " + myEEData.ManufacturerID.ToString());
Console.WriteLine("Description: " + myEEData.Description.ToString());
Console.WriteLine("Serial Number: " + myEEData.SerialNumber.ToString());
Console.WriteLine("Max Power: " + myEEData.MaxPower.ToString() + "mA");
Console.WriteLine("Self Powered: " + myEEData.SelfPowered.ToString());
Console.WriteLine("Remote Wakeup Enabled: " + myEEData.RemoteWakeup.ToString());
Console.WriteLine("");
// Change our serial number to write back to device
// By setting to an empty string, we allow the FTD2XX DLL
// to generate a serial number
myEEData.SerialNumber = String.Empty;
// Write our modified data structure back to the device EEPROM
// This can throw an exception if trying to write a device type that does not
// match the EEPROM structure being used, so should always use a
// try - catch block when calling
try
{
ftStatus = myFtdiDevice.WriteFT232BEEPROM(myEEData);
}
catch (FTDI.FT_EXCEPTION)
{
Console.WriteLine("Exception thrown when calling WriteFT232BEEPROM");
}
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
// Wait for a key press
Console.WriteLine("Failed to write device EEPROM (error " + ftStatus.ToString() + ")");
Console.ReadKey();
// Close the device
myFtdiDevice.Close();
return;
}
}
// Use cycle port to force a re-enumeration of the device.
// In the FTD2XX_NET class library, the cycle port method also
// closes the open handle so no need to call the Close method separately.
ftStatus = myFtdiDevice.CyclePort();
UInt32 newFtdiDeviceCount = 0;
do
{
// Wait for device to be re-enumerated
// The device will have the same location since it has not been
// physically unplugged, so we will keep trying to open it until it succeeds
ftStatus = myFtdiDevice.OpenByLocation(ftdiDeviceList[0].LocId);
Thread.Sleep(1000);
} while (ftStatus != FTDI.FT_STATUS.FT_OK);
// Close the device
myFtdiDevice.Close();
// Re-create our device list
ftStatus = myFtdiDevice.GetNumberOfDevices(ref newFtdiDeviceCount);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
// Wait for a key press
Console.WriteLine("Failed to get number of devices (error " + ftStatus.ToString() + ")");
Console.ReadKey();
return;
}
// Re-populate our device list
ftStatus = myFtdiDevice.GetDeviceList(ftdiDeviceList);
if (ftStatus == FTDI.FT_STATUS.FT_OK)
{
for (UInt32 i = 0; i < ftdiDeviceCount; i++)
{
Console.WriteLine("Device Index: " + i.ToString());
Console.WriteLine("Flags: " + String.Format("{0:x}", ftdiDeviceList[i].Flags));
Console.WriteLine("Type: " + ftdiDeviceList[i].Type.ToString());
Console.WriteLine("ID: " + String.Format("{0:x}", ftdiDeviceList[i].ID));
Console.WriteLine("Location ID: " + String.Format("{0:x}", ftdiDeviceList[i].LocId));
Console.WriteLine("Serial Number: " + ftdiDeviceList[i].SerialNumber.ToString());
Console.WriteLine("Description: " + ftdiDeviceList[i].Description.ToString());
Console.WriteLine("");
}
}
// Wait for a key press
Console.WriteLine("Press any key to continue.");
Console.ReadKey();
return;
}
}
}

View File

@@ -0,0 +1,33 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("EEPROM")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("FTDI")]
[assembly: AssemblyProduct("EEPROM")]
[assembly: AssemblyCopyright("Copyright © FTDI 2008")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("4276d0d9-348e-4699-ba99-1b72708463d2")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -0,0 +1,84 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="14.0">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.50727</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{2256AEA0-6A5A-4506-9F4B-99AB11C0ECA0}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>EEPROM</RootNamespace>
<AssemblyName>EEPROM</AssemblyName>
<SccProjectName>SAK</SccProjectName>
<SccLocalPath>SAK</SccLocalPath>
<SccAuxPath>SAK</SccAuxPath>
<SccProvider>SAK</SccProvider>
<TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
<FileUpgradeFlags>
</FileUpgradeFlags>
<UpgradeBackupLocation>
</UpgradeBackupLocation>
<OldToolsVersion>2.0</OldToolsVersion>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="FTD2XX_NET, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>.\FTD2XX_NET.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>true</Install>
</BootstrapperPackage>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<PublishUrlHistory />
<InstallUrlHistory />
<SupportUrlHistory />
<UpdateUrlHistory />
<BootstrapperUrlHistory />
<ErrorReportUrlHistory />
<FallbackCulture>en-US</FallbackCulture>
<VerifyUploadedFiles>false</VerifyUploadedFiles>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,22 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.24720.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EEPROM", "EEPROM.csproj", "{2256AEA0-6A5A-4506-9F4B-99AB11C0ECA0}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{2256AEA0-6A5A-4506-9F4B-99AB11C0ECA0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2256AEA0-6A5A-4506-9F4B-99AB11C0ECA0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2256AEA0-6A5A-4506-9F4B-99AB11C0ECA0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2256AEA0-6A5A-4506-9F4B-99AB11C0ECA0}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,347 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using FTD2XX_NET;
namespace EEPROM
{
class Program
{
static void Main(string[] args)
{
UInt32 ftdiDeviceCount = 0;
FTDI.FT_STATUS ftStatus = FTDI.FT_STATUS.FT_OK;
// Create new instance of the FTDI device class
FTDI myFtdiDevice = new FTDI();
// Determine the number of FTDI devices connected to the machine
ftStatus = myFtdiDevice.GetNumberOfDevices(ref ftdiDeviceCount);
// Check status
if (ftStatus == FTDI.FT_STATUS.FT_OK)
{
Console.WriteLine("Number of FTDI devices: " + ftdiDeviceCount.ToString());
Console.WriteLine("");
}
else
{
// Wait for a key press
Console.WriteLine("Failed to get number of devices (error " + ftStatus.ToString() + ")");
Console.ReadKey();
return;
}
// If no devices available, return
if (ftdiDeviceCount == 0)
{
// Wait for a key press
Console.WriteLine("Failed to get number of devices (error " + ftStatus.ToString() + ")");
Console.ReadKey();
return;
}
// Allocate storage for device info list
FTDI.FT_DEVICE_INFO_NODE[] ftdiDeviceList = new FTDI.FT_DEVICE_INFO_NODE[ftdiDeviceCount];
// Populate our device list
ftStatus = myFtdiDevice.GetDeviceList(ftdiDeviceList);
if (ftStatus == FTDI.FT_STATUS.FT_OK)
{
for (UInt32 i = 0; i < ftdiDeviceCount; i++)
{
Console.WriteLine("Device Index: " + i.ToString());
Console.WriteLine("Flags: " + String.Format("{0:x}", ftdiDeviceList[i].Flags));
Console.WriteLine("Type: " + ftdiDeviceList[i].Type.ToString());
Console.WriteLine("ID: " + String.Format("{0:x}", ftdiDeviceList[i].ID));
Console.WriteLine("Location ID: " + String.Format("{0:x}", ftdiDeviceList[i].LocId));
Console.WriteLine("Serial Number: " + ftdiDeviceList[i].SerialNumber.ToString());
Console.WriteLine("Description: " + ftdiDeviceList[i].Description.ToString());
Console.WriteLine("");
}
}
// Open first device in our list by serial number
ftStatus = myFtdiDevice.OpenBySerialNumber(ftdiDeviceList[0].SerialNumber);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
// Wait for a key press
Console.WriteLine("Failed to open device (error " + ftStatus.ToString() + ")");
Console.ReadKey();
return;
}
// Create our device EEPROM structure based on the type of device we have open
if (ftdiDeviceList[0].Type == FTDI.FT_DEVICE.FT_DEVICE_232R)
{
// We have an FT232R or FT245R so use FT232R EEPROM structure
FTDI.FT232R_EEPROM_STRUCTURE myEEData = new FTDI.FT232R_EEPROM_STRUCTURE();
// Read the device EEPROM
// This can throw an exception if trying to read a device type that does not
// match the EEPROM structure being used, so should always use a
// try - catch block when calling
try
{
ftStatus = myFtdiDevice.ReadFT232REEPROM(myEEData);
}
catch (FTDI.FT_EXCEPTION)
{
Console.WriteLine("Exception thrown when calling ReadFT232REEPROM");
}
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
// Wait for a key press
Console.WriteLine("Failed to read device EEPROM (error " + ftStatus.ToString() + ")");
Console.ReadKey();
// Close the device
myFtdiDevice.Close();
return;
}
// Write common EEPROM elements to our console
Console.WriteLine("EEPROM Contents for device at index 0:");
Console.WriteLine("Vendor ID: " + String.Format("{0:x}", myEEData.VendorID));
Console.WriteLine("Product ID: " + String.Format("{0:x}", myEEData.ProductID));
Console.WriteLine("Manufacturer: " + myEEData.Manufacturer.ToString());
Console.WriteLine("Manufacturer ID: " + myEEData.ManufacturerID.ToString());
Console.WriteLine("Description: " + myEEData.Description.ToString());
Console.WriteLine("Serial Number: " + myEEData.SerialNumber.ToString());
Console.WriteLine("Max Power: " + myEEData.MaxPower.ToString() + "mA");
Console.WriteLine("Self Powered: " + myEEData.SelfPowered.ToString());
Console.WriteLine("Remote Wakeup Enabled: " + myEEData.RemoteWakeup.ToString());
Console.WriteLine("");
// Change our serial number to write back to device
// By setting to an empty string, we allow the FTD2XX DLL
// to generate a serial number
//myEEData.SerialNumber = String.Empty;
// Wim: Set to defined string
myEEData.SerialNumber ="ChamChat_01";
myEEData.Description = "FDTI_USB_COM422_WE";
// Write our modified data structure back to the device EEPROM
// This can throw an exception if trying to write a device type that does not
// match the EEPROM structure being used, so should always use a
// try - catch block when calling
try
{
ftStatus = myFtdiDevice.WriteFT232REEPROM(myEEData);
}
catch (FTDI.FT_EXCEPTION)
{
Console.WriteLine("Exception thrown when calling WriteFT232REEPROM");
}
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
// Wait for a key press
Console.WriteLine("Failed to write device EEPROM (error " + ftStatus.ToString() + ")");
Console.ReadKey();
// Close the device
myFtdiDevice.Close();
return;
}
}
else if (ftdiDeviceList[0].Type == FTDI.FT_DEVICE.FT_DEVICE_2232)
{
// We have an FT2232 so use FT2232 EEPROM structure
FTDI.FT2232_EEPROM_STRUCTURE myEEData = new FTDI.FT2232_EEPROM_STRUCTURE();
// Read the device EEPROM
ftStatus = myFtdiDevice.ReadFT2232EEPROM(myEEData);
// This can throw an exception if trying to read a device type that does not
// match the EEPROM structure being used, so should always use a
// try - catch block when calling
try
{
ftStatus = myFtdiDevice.ReadFT2232EEPROM(myEEData);
}
catch (FTDI.FT_EXCEPTION)
{
Console.WriteLine("Exception thrown when calling ReadFT2232EEPROM");
}
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
// Wait for a key press
Console.WriteLine("Failed to read device EEPROM (error " + ftStatus.ToString() + ")");
Console.ReadKey();
// Close the device
myFtdiDevice.Close();
return;
}
// Write common EEPROM elements to our console
Console.WriteLine("EEPROM Contents for device at index 0:");
Console.WriteLine("Vendor ID: " + String.Format("{0:x}", myEEData.VendorID));
Console.WriteLine("Product ID: " + String.Format("{0:x}", myEEData.ProductID));
Console.WriteLine("Manufacturer: " + myEEData.Manufacturer.ToString());
Console.WriteLine("Manufacturer ID: " + myEEData.ManufacturerID.ToString());
Console.WriteLine("Description: " + myEEData.Description.ToString());
Console.WriteLine("Serial Number: " + myEEData.SerialNumber.ToString());
Console.WriteLine("Max Power: " + myEEData.MaxPower.ToString() + "mA");
Console.WriteLine("Self Powered: " + myEEData.SelfPowered.ToString());
Console.WriteLine("Remote Wakeup Enabled: " + myEEData.RemoteWakeup.ToString());
Console.WriteLine("");
// Change our serial number to write back to device
// By setting to an empty string, we allow the FTD2XX DLL
// to generate a serial number
myEEData.SerialNumber = String.Empty;
// Write our modified data structure back to the device EEPROM
// This can throw an exception if trying to write a device type that does not
// match the EEPROM structure being used, so should always use a
// try - catch block when calling
try
{
ftStatus = myFtdiDevice.WriteFT2232EEPROM(myEEData);
}
catch (FTDI.FT_EXCEPTION)
{
Console.WriteLine("Exception thrown when calling WriteFT2232EEPROM");
}
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
// Wait for a key press
Console.WriteLine("Failed to write device EEPROM (error " + ftStatus.ToString() + ")");
Console.ReadKey();
// Close the device
myFtdiDevice.Close();
return;
}
}
else if (ftdiDeviceList[0].Type == FTDI.FT_DEVICE.FT_DEVICE_BM)
{
// We have an FT232B or FT245B so use FT232B EEPROM structure
FTDI.FT232B_EEPROM_STRUCTURE myEEData = new FTDI.FT232B_EEPROM_STRUCTURE();
// Read the device EEPROM
ftStatus = myFtdiDevice.ReadFT232BEEPROM(myEEData);
// This can throw an exception if trying to read a device type that does not
// match the EEPROM structure being used, so should always use a
// try - catch block when calling
try
{
ftStatus = myFtdiDevice.ReadFT232BEEPROM(myEEData);
}
catch (FTDI.FT_EXCEPTION)
{
Console.WriteLine("Exception thrown when calling ReadFT232BEEPROM");
}
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
// Wait for a key press
Console.WriteLine("Failed to read device EEPROM (error " + ftStatus.ToString() + ")");
Console.ReadKey();
// Close the device
myFtdiDevice.Close();
return;
}
// Write common EEPROM elements to our console
Console.WriteLine("EEPROM Contents for device at index 0:");
Console.WriteLine("Vendor ID: " + String.Format("{0:x}", myEEData.VendorID));
Console.WriteLine("Product ID: " + String.Format("{0:x}", myEEData.ProductID));
Console.WriteLine("Manufacturer: " + myEEData.Manufacturer.ToString());
Console.WriteLine("Manufacturer ID: " + myEEData.ManufacturerID.ToString());
Console.WriteLine("Description: " + myEEData.Description.ToString());
Console.WriteLine("Serial Number: " + myEEData.SerialNumber.ToString());
Console.WriteLine("Max Power: " + myEEData.MaxPower.ToString() + "mA");
Console.WriteLine("Self Powered: " + myEEData.SelfPowered.ToString());
Console.WriteLine("Remote Wakeup Enabled: " + myEEData.RemoteWakeup.ToString());
Console.WriteLine("");
// Change our serial number to write back to device
// By setting to an empty string, we allow the FTD2XX DLL
// to generate a serial number
myEEData.SerialNumber = String.Empty;
// Write our modified data structure back to the device EEPROM
// This can throw an exception if trying to write a device type that does not
// match the EEPROM structure being used, so should always use a
// try - catch block when calling
try
{
ftStatus = myFtdiDevice.WriteFT232BEEPROM(myEEData);
}
catch (FTDI.FT_EXCEPTION)
{
Console.WriteLine("Exception thrown when calling WriteFT232BEEPROM");
}
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
// Wait for a key press
Console.WriteLine("Failed to write device EEPROM (error " + ftStatus.ToString() + ")");
Console.ReadKey();
// Close the device
myFtdiDevice.Close();
return;
}
}
// Use cycle port to force a re-enumeration of the device.
// In the FTD2XX_NET class library, the cycle port method also
// closes the open handle so no need to call the Close method separately.
ftStatus = myFtdiDevice.CyclePort();
UInt32 newFtdiDeviceCount = 0;
do
{
// Wait for device to be re-enumerated
// The device will have the same location since it has not been
// physically unplugged, so we will keep trying to open it until it succeeds
ftStatus = myFtdiDevice.OpenByLocation(ftdiDeviceList[0].LocId);
Thread.Sleep(1000);
} while (ftStatus != FTDI.FT_STATUS.FT_OK);
// Close the device
myFtdiDevice.Close();
// Re-create our device list
ftStatus = myFtdiDevice.GetNumberOfDevices(ref newFtdiDeviceCount);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
// Wait for a key press
Console.WriteLine("Failed to get number of devices (error " + ftStatus.ToString() + ")");
Console.ReadKey();
return;
}
// Re-populate our device list
ftStatus = myFtdiDevice.GetDeviceList(ftdiDeviceList);
if (ftStatus == FTDI.FT_STATUS.FT_OK)
{
for (UInt32 i = 0; i < ftdiDeviceCount; i++)
{
Console.WriteLine("Device Index: " + i.ToString());
Console.WriteLine("Flags: " + String.Format("{0:x}", ftdiDeviceList[i].Flags));
Console.WriteLine("Type: " + ftdiDeviceList[i].Type.ToString());
Console.WriteLine("ID: " + String.Format("{0:x}", ftdiDeviceList[i].ID));
Console.WriteLine("Location ID: " + String.Format("{0:x}", ftdiDeviceList[i].LocId));
Console.WriteLine("Serial Number: " + ftdiDeviceList[i].SerialNumber.ToString());
Console.WriteLine("Description: " + ftdiDeviceList[i].Description.ToString());
Console.WriteLine("");
}
}
// Wait for a key press
Console.WriteLine("Press any key to continue.");
Console.ReadKey();
return;
}
}
}

View File

@@ -0,0 +1,33 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("EEPROM")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("FTDI")]
[assembly: AssemblyProduct("EEPROM")]
[assembly: AssemblyCopyright("Copyright © FTDI 2008")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("4276d0d9-348e-4699-ba99-1b72708463d2")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

Binary file not shown.

102
ChamChat/ChamChat.sln Normal file
View File

@@ -0,0 +1,102 @@

Microsoft Visual Studio Solution File, Format Version 11.00
# Visual C# Express 2010
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChamChat", "ChamChat\ChamChat.csproj", "{CB29FF5C-CB83-48A3-96EC-E7D08DDEFF58}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Models", "Models\Models.csproj", "{09375A4A-28B8-427B-853D-75C03A070728}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Client_HTS7057", "Client_HTS7057\Client_HTS7057.csproj", "{B03537FE-EF64-42E3-A8C0-25C79BB818A7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Client_LHL113", "Client_LHL113\Client_LHL113.csproj", "{162E2D74-E197-4188-A3B2-B33B827CC519}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Client_TSx", "Client_TSx\Client_TSx.csproj", "{A863C309-E15C-4EA1-82F2-BDFE83C96D15}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Client_PLxKPH", "Client_PLxKPH\Client_PLxKPH.csproj", "{1FB70C9C-6F0B-4580-9682-A85B40C90B38}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Client_Watlow988U", "Client_Watlow988U\Client_Watlow988U.csproj", "{5698A508-3CFD-4570-AC10-86B9B40F0C23}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|Mixed Platforms = Debug|Mixed Platforms
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|Mixed Platforms = Release|Mixed Platforms
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{CB29FF5C-CB83-48A3-96EC-E7D08DDEFF58}.Debug|Any CPU.ActiveCfg = Debug|x86
{CB29FF5C-CB83-48A3-96EC-E7D08DDEFF58}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
{CB29FF5C-CB83-48A3-96EC-E7D08DDEFF58}.Debug|Mixed Platforms.Build.0 = Debug|x86
{CB29FF5C-CB83-48A3-96EC-E7D08DDEFF58}.Debug|x86.ActiveCfg = Debug|x86
{CB29FF5C-CB83-48A3-96EC-E7D08DDEFF58}.Debug|x86.Build.0 = Debug|x86
{CB29FF5C-CB83-48A3-96EC-E7D08DDEFF58}.Release|Any CPU.ActiveCfg = Release|x86
{CB29FF5C-CB83-48A3-96EC-E7D08DDEFF58}.Release|Mixed Platforms.ActiveCfg = Release|x86
{CB29FF5C-CB83-48A3-96EC-E7D08DDEFF58}.Release|Mixed Platforms.Build.0 = Release|x86
{CB29FF5C-CB83-48A3-96EC-E7D08DDEFF58}.Release|x86.ActiveCfg = Release|x86
{CB29FF5C-CB83-48A3-96EC-E7D08DDEFF58}.Release|x86.Build.0 = Release|x86
{09375A4A-28B8-427B-853D-75C03A070728}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{09375A4A-28B8-427B-853D-75C03A070728}.Debug|Any CPU.Build.0 = Debug|Any CPU
{09375A4A-28B8-427B-853D-75C03A070728}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{09375A4A-28B8-427B-853D-75C03A070728}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{09375A4A-28B8-427B-853D-75C03A070728}.Debug|x86.ActiveCfg = Debug|Any CPU
{09375A4A-28B8-427B-853D-75C03A070728}.Release|Any CPU.ActiveCfg = Release|Any CPU
{09375A4A-28B8-427B-853D-75C03A070728}.Release|Any CPU.Build.0 = Release|Any CPU
{09375A4A-28B8-427B-853D-75C03A070728}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{09375A4A-28B8-427B-853D-75C03A070728}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{09375A4A-28B8-427B-853D-75C03A070728}.Release|x86.ActiveCfg = Release|Any CPU
{B03537FE-EF64-42E3-A8C0-25C79BB818A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B03537FE-EF64-42E3-A8C0-25C79BB818A7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B03537FE-EF64-42E3-A8C0-25C79BB818A7}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{B03537FE-EF64-42E3-A8C0-25C79BB818A7}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{B03537FE-EF64-42E3-A8C0-25C79BB818A7}.Debug|x86.ActiveCfg = Debug|Any CPU
{B03537FE-EF64-42E3-A8C0-25C79BB818A7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B03537FE-EF64-42E3-A8C0-25C79BB818A7}.Release|Any CPU.Build.0 = Release|Any CPU
{B03537FE-EF64-42E3-A8C0-25C79BB818A7}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{B03537FE-EF64-42E3-A8C0-25C79BB818A7}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{B03537FE-EF64-42E3-A8C0-25C79BB818A7}.Release|x86.ActiveCfg = Release|Any CPU
{162E2D74-E197-4188-A3B2-B33B827CC519}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{162E2D74-E197-4188-A3B2-B33B827CC519}.Debug|Any CPU.Build.0 = Debug|Any CPU
{162E2D74-E197-4188-A3B2-B33B827CC519}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{162E2D74-E197-4188-A3B2-B33B827CC519}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{162E2D74-E197-4188-A3B2-B33B827CC519}.Debug|x86.ActiveCfg = Debug|Any CPU
{162E2D74-E197-4188-A3B2-B33B827CC519}.Release|Any CPU.ActiveCfg = Release|Any CPU
{162E2D74-E197-4188-A3B2-B33B827CC519}.Release|Any CPU.Build.0 = Release|Any CPU
{162E2D74-E197-4188-A3B2-B33B827CC519}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{162E2D74-E197-4188-A3B2-B33B827CC519}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{162E2D74-E197-4188-A3B2-B33B827CC519}.Release|x86.ActiveCfg = Release|Any CPU
{A863C309-E15C-4EA1-82F2-BDFE83C96D15}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A863C309-E15C-4EA1-82F2-BDFE83C96D15}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A863C309-E15C-4EA1-82F2-BDFE83C96D15}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{A863C309-E15C-4EA1-82F2-BDFE83C96D15}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{A863C309-E15C-4EA1-82F2-BDFE83C96D15}.Debug|x86.ActiveCfg = Debug|Any CPU
{A863C309-E15C-4EA1-82F2-BDFE83C96D15}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A863C309-E15C-4EA1-82F2-BDFE83C96D15}.Release|Any CPU.Build.0 = Release|Any CPU
{A863C309-E15C-4EA1-82F2-BDFE83C96D15}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{A863C309-E15C-4EA1-82F2-BDFE83C96D15}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{A863C309-E15C-4EA1-82F2-BDFE83C96D15}.Release|x86.ActiveCfg = Release|Any CPU
{1FB70C9C-6F0B-4580-9682-A85B40C90B38}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1FB70C9C-6F0B-4580-9682-A85B40C90B38}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1FB70C9C-6F0B-4580-9682-A85B40C90B38}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{1FB70C9C-6F0B-4580-9682-A85B40C90B38}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{1FB70C9C-6F0B-4580-9682-A85B40C90B38}.Debug|x86.ActiveCfg = Debug|Any CPU
{1FB70C9C-6F0B-4580-9682-A85B40C90B38}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1FB70C9C-6F0B-4580-9682-A85B40C90B38}.Release|Any CPU.Build.0 = Release|Any CPU
{1FB70C9C-6F0B-4580-9682-A85B40C90B38}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{1FB70C9C-6F0B-4580-9682-A85B40C90B38}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{1FB70C9C-6F0B-4580-9682-A85B40C90B38}.Release|x86.ActiveCfg = Release|Any CPU
{5698A508-3CFD-4570-AC10-86B9B40F0C23}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5698A508-3CFD-4570-AC10-86B9B40F0C23}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5698A508-3CFD-4570-AC10-86B9B40F0C23}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{5698A508-3CFD-4570-AC10-86B9B40F0C23}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{5698A508-3CFD-4570-AC10-86B9B40F0C23}.Debug|x86.ActiveCfg = Debug|Any CPU
{5698A508-3CFD-4570-AC10-86B9B40F0C23}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5698A508-3CFD-4570-AC10-86B9B40F0C23}.Release|Any CPU.Build.0 = Release|Any CPU
{5698A508-3CFD-4570-AC10-86B9B40F0C23}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{5698A508-3CFD-4570-AC10-86B9B40F0C23}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{5698A508-3CFD-4570-AC10-86B9B40F0C23}.Release|x86.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

BIN
ChamChat/ChamChat.suo Normal file

Binary file not shown.

1566
ChamChat/ChamChat/ChamChat.Designer.cs generated Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,137 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{CB29FF5C-CB83-48A3-96EC-E7D08DDEFF58}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>ChamChat</RootNamespace>
<AssemblyName>ChamChat</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkProfile>
</TargetFrameworkProfile>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<PlatformTarget>x86</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<PlatformTarget>x86</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>icon.ico</ApplicationIcon>
</PropertyGroup>
<PropertyGroup>
<StartupObject>
</StartupObject>
</PropertyGroup>
<ItemGroup>
<Reference Include="FTD2XX_NET">
<HintPath>..\Lib\FTD2XX_NET.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Clients.cs" />
<Compile Include="Interface.FDTI_USB_RS232.cs" />
<Compile Include="Interface.FDTI_USB_RS485.cs" />
<Compile Include="Graph.cs" />
<Compile Include="Interfaces.cs" />
<Compile Include="Layouts.cs" />
<Compile Include="Interface.FDTI_USB_RS422.cs" />
<Compile Include="PromptProgramNo.cs" />
<Compile Include="ChamChat.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="ChamChat.Designer.cs">
<DependentUpon>ChamChat.cs</DependentUpon>
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<EmbeddedResource Include="ChamChat.resx">
<DependentUpon>ChamChat.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
<DesignTime>True</DesignTime>
</Compile>
<None Include="app.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
</ItemGroup>
<ItemGroup>
<Content Include="icon.ico" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Client_HTS7057\Client_HTS7057.csproj">
<Project>{B03537FE-EF64-42E3-A8C0-25C79BB818A7}</Project>
<Name>Client_HTS7057</Name>
</ProjectReference>
<ProjectReference Include="..\Client_LHL113\Client_LHL113.csproj">
<Project>{162E2D74-E197-4188-A3B2-B33B827CC519}</Project>
<Name>Client_LHL113</Name>
</ProjectReference>
<ProjectReference Include="..\Client_PLxKPH\Client_PLxKPH.csproj">
<Project>{1FB70C9C-6F0B-4580-9682-A85B40C90B38}</Project>
<Name>Client_PLxKPH</Name>
</ProjectReference>
<ProjectReference Include="..\Client_TSx\Client_TSx.csproj">
<Project>{A863C309-E15C-4EA1-82F2-BDFE83C96D15}</Project>
<Name>Client_TSx</Name>
</ProjectReference>
<ProjectReference Include="..\Client_Watlow988U\Client_Watlow988U.csproj">
<Project>{5698A508-3CFD-4570-AC10-86B9B40F0C23}</Project>
<Name>Client_Watlow988U</Name>
</ProjectReference>
<ProjectReference Include="..\Models\Models.csproj">
<Project>{09375A4A-28B8-427B-853D-75C03A070728}</Project>
<Name>Models</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
</Project>

View File

@@ -0,0 +1,615 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="contextMenuStrip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>577, 17</value>
</metadata>
<metadata name="dgvLoopsColumnFirst.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="dgvLoopsColumnLast.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="dgvLoopsColumnN.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="dataGridViewTextBoxColumn1.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="dgvProfileColumnStep.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="dgvProfileColumnT.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="dgvProfileColumnRH.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="dgvProfileColumnRampCtrlT.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="dgvProfileColumnRampCtrlRH.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="dgvProfileColumnPreT.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="dgvProfileColumnLimit.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="dgvProfileColumnDurationHr.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="dgvProfileColumnDurationMin.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="dgvTasksColumnDescription.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="dgvTasksColumnDescription.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="timerUpdateTask.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>157, 17</value>
</metadata>
<metadata name="sfdSave.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>301, 17</value>
</metadata>
<metadata name="menu.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>494, 17</value>
</metadata>
<metadata name="ofdOpen.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>394, 17</value>
</metadata>
<metadata name="bgworkerImport.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="bgworkerExport.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>724, 14</value>
</metadata>
<metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>51</value>
</metadata>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
AAABAAkAMDAQAAEABABoBgAAlgAAACAgEAABAAQA6AIAAP4GAAAQEBAAAQAEACgBAADmCQAAMDAAAAEA
CACoDgAADgsAACAgAAABAAgAqAgAALYZAAAQEAAAAQAIAGgFAABeIgAAMDAAAAEAIACoJQAAxicAACAg
AAABACAAqBAAAG5NAAAQEAAAAQAgAGgEAAAWXgAAKAAAADAAAABgAAAAAQAEAAAAAAAABgAAAAAAAAAA
AAAQAAAAEAAAAAAAAAAAAIAAAIAAAACAgACAAAAAgACAAICAAACAgIAAwMDAAAAA/wAA/wAAAP//AP8A
AAD/AP8A//8AAP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUlBSUnBzQ2UAAAAA
AAAAAAAAAAAAAAAQAAAAABQUN1JxcWAAAAAAAAAAAAAAAQUAEAEAEAAgBDVjZXFgAAAAAAAAAAAUJAAA
QAQAAEAUIQcHUnJwAAAAAAAAAAEAEHAAEAIUADBAFAJSdSV3cAAAAAAABwAFBABwQlBDBQQwQlAENDcH
BwAAAAAAQBQAA0EFJQcBQ0NBJQJQFnRzQwAAAAACEAAFBBBgU0FhYXBSUCUGBBYWdwAAAAAFBBQgEgUD
QlJQcGFhYFJQFgcXAAAAAABgAAEFBQFwUQcWE1NDQWEGAAFgcAAAAAAEEkFhIXAXBxQxQ1MRYUJQFCR3
AAAAAAQQBBAQUBYWEDEXExE1ElAAAAEAAAAAAABAcAcBA0ERFxc5OXExYSUgFAQlAAAAAEElBQEHBRMT
ebk5cTMXElAUAAEEIAAAAFJBIBYQExeXm5OTExcTFSFBBAADQAAAUAQwUFAUCXm5g5cTFBE1MUEwAwFA
AAAABhBSATBRc4ubmTOXExFxMTFBBAAhYQAABBYAEFMDE5N5c5iTEXEblzExEAFABAAABwFDQTUVNzEx
k5c3ERMXm5eXABABJAAHBAABEBETNxNTcbiYExl5t5MTFQIEAAAAcFBSU3E3Fxc1OXl7lROTm3FxEwUC
UHAEEAABOTU1JSU3lbg4MTF5NTExNQEAASAAQBQ3FzNTU1NZObebEVMTETeTAxJBQEAABAEBcxdxYXFx
OYl5cxE1Nbc1EFEAAHAAUBYXBTdSVxMDE7V7kXMVN5cSFAYQFCAAAABQN1JWU3EVGYublxUTlzMFAwEE
AHAEEFAldWd3NTExEYOJMTFxOYMSUBIBQAAAAABQdzV2VzFRE3k3MVE5cxFBJQVAMAAABQFzU3d1cTkx
eXN5MTETlTAxUhIWBAAAAAAAdXVnE1NTU3l3EReXMxcXAWVAFgAABQdXV3dxYRc3NTc5NTE5eXE1NxIW
AAAAAABEd3d0Fzd5cXlxMTl5MXFhdWBBQAAAAFB3d2Uhd5eXNRcRFTEzVzVzUlAGcAAAAAdHd3dTE3d3
kxMXExcXMXNXZQQwAAAAAAR3dXNBdxc3MXFxF1NxRxdwcHBHAAAAAAFndlcSU3FxAxMTUxNBMHUlBwFg
AAAAAAZWdXFlNQEUEXERMFAWFSFSUHQAAAAAAABWd3ZTQSUlIRNTUwNQNBR3Z0cAAAAAAAAHR0cWEBAR
FXV1dRUhYWF0dWAAAAAAAAAAdzQAAAEDV3h4dzYUFDR3ZwAAAAAAAAAABAEAEEB0d4iHdUElIGV0cAAA
AAAAAAAAAEAUABABZ3iHdyUABSVgAAAAAAAAAAAAAAAAFABBR1d2UAA0JWUAAAAAAAAAAAAAAAAAAAEA
AGBUBBBBQAAAAAAAAAAAAAAAAAAAAAAAEAEAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////8AAP//////+AAAB//////AAAAB/////w
AAAAD////+AAAAAH////gAAAAAP///8AAAAAA////gAAAAAD///8AAAAAAf///wAAAAAB///+AAAAAAP
///wAAAAAA////AAAAAAD///4AAAAAAH///gAAAAAAf//8AAAAAAB///wAAAAAAD///AAAAAAAP//8AA
AAAAA///gAAAAAAD//+AAAAAAAH//4AAAAAAAf//gAAAAAAB//+AAAAAAAH//4AAAAAAAf//gAAAAAAB
//+AAAAAAAP//8AAAAAAA///wAAAAAAD///AAAAAAAP//8AAAAAAB///4AAAAAAH///gAAAAAAf///AA
AAAAD///8AAAAAAP///4AAAAAB////gAAAAAP////AAAAAA////+AAAAAH////8AAAAA/////4AAAAH/
////wAAAB//////wAAAP//////wAAD///////wAA////////8A////////////////8oAAAAIAAAAEAA
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
///wAAAAAA///+AAAAAAB///4AAAAAAH///AAAAAAAf//8AAAAAAA///wAAAAAAD///AAAAAAAP//4AA
AAAAA///gAAAAAAB//+AAAAAAAH//4AAAAAAAf//gAAAAAAB//+AAAAAAAH//4AAAAAAAf//gAAAAAAD
///AAAAAAAP//8AAAAAAA///wAAAAAAD///AAAAAAAf//+AAAAAAB///4AAAAAAH///wAAAAAA////AA
AAAAD///+AAAAAAf///4AAAAAD////wAAAAAP////gAAAAB/////AAAAAP////+AAAAB/////8AAAAf/
////8AAAD//////8AAA///////8AAP////////AP////////////////KAAAACAAAABAAAAAAQAIAAAA
AACABAAAAAAAAAAAAAAAAQAAAAEAAAAAAAAkFRoANRsnAEY0OQApa7oAEhptACU5iQBmV2cAdmVvABky
eQBDNEQAJ0iVABkaRwAXNocANShFACojOABDN1YAIyllACskJwApM2cAOEl4ADQ0VQBTSWYAFCqFAHZZ
WgBHR2oARUp3ACc3dgB5ZpMANDx2ADl5xwAZEhoAEgMaAI95lwA4O2YAQigrABlZyQCLY1YAT4vQAEY0
LAA0Y6oAFCyVACVTpwAoTKYAR3fEABxCkQBhRDsAJRtGACUTIwAUCRoAGkmzADVWpgBmVVwAWHW5ACwk
HgAbCiIAK0R6ACMMIwAaChsAGgMcADsyOABRS00AKVSaABtXtAArHSwAelhKACoyVwAUCiMAJWLHAHhe
aQAkGSwAVEl3ACscMwAkU8YAWUlZACocJAA7KjMAREJcACIiUgAkEywAOSo6ABc+tQCUbWgAJFa8ACQj
SgBKLjcAJmrpABktewBoSEQAhltRADRGhAAUKm4AV1mXAA46mgCKZGQAIhs8ACsTJABiVXgAOGa8ADsz
KgAcESEANCksAGBKWQCYdncAJCpVACsNHQAZJGoACwooACVDgwAcFTwAJ062ACwrSwAhG1MADQMTABkE
IwA4IysAHQoqAAwEGwAxIiIAGzuUACIVPAAbLlsAPCsmAJV0bgA0YpoAGSRjADIiMgBHU4gACQobAENt
rAAWGz0AKiJCAB4jTQA0JCwAMCxUABQ2mgAoLFwAHSxkADQoOwBdUGsAJBo2ACEFHQBOTUwAFSt5ABor
dQA8gNAAMzRCADEZHAAfHCwAFSVaAFJRUgBtUEUAJSBCADUrMgAmGSEAGSJcABUDIwAyJD0AOThCABcp
cAAiEzAAuZKQAEJBRQAQBBcAFz2hAE1ETQA+NUYAPjNOAD06TwAVNZEAGzSRABs0nAAfOJkAFxcwABkT
MgAWFjkAEiNUAB0gVAAVD0IAWWCHAExmngBTYJ0AGhIsAAgIFwAqTIUAIUCNACROjwAvS44AFSJxACIE
FgAiCB8AFWjlAB1+4wAdePUAIHDkADZ86QANRsgAGU/CACgjVAArKlEAKSlAACwkSwAlKk8AEiVnABAl
bgAZLW8AJi+CADM/iwAkP5YAGkCkABlUrAA+IiYAMykjADkqKgBTbagAQ22wADSX8AA6JToAQUeMAFBZ
hgBGTpYAOEBqAKWFqwC6o7EAH0V/AIZxbwCAY3AAFAkXAB4LFwBhR2gAVTVDAC1xugAqFS0AUCcwADFM
oAA4XLMAx6i+AD1owQAgadYAMGjXACd01AAyU4sAMkyXAD1TlQBeV3YAdk5GAA8tgwAWNGoAEQk0ACA+
pgA5HTAAHmDKAH9gTAAAAAAAGAwOAKWCeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAENDdSAgMUOUD6KOlpaWAAAAAAAAAAAAAAAAAAAAN086o3FxcXFxIGQfHxKilpaWlpYA
AAAAAAAAAAAAAo05YDA6AQEwMDdkmktLS0s8PZaWlpYAAAAAAAAAADk7OzkwS4VzTEx+D4pQmWWFQEtj
PZaWlgAAAAAAAAA5OzuNME9GflAK2VCoCgM8mWVlZQJ6jpaWAAAAAAAAkzo7OehIjJgODg4QEJKepp48
TExlmgE8PZYAAAAAAJMB5GBILy9Ux4YVymhCiDi5Ww48ZQEgOpoDAAAAAAAAaQEwQG0MeINUToSweQmP
WwkbFZISZDsgOnYAAAAAAGlgQEigLwwMsYl9BkTuxTI/KuBCbw+gMSAxAWMAAAAAaQJQSIxteHifBERW
vyRdV2oJbImEVG1DOjEfEgAAANMCfki2DE4vTgTYwlbEU3ePapB3LfeVm/g3MTE2AAAAAnMwoG2bEU4b
5z8rU1HtMwnMF4fwBA1XskM6Hx96AAAjYDdfDAwRCSh8OBQrKywsLQUXScHAKgt9rh8fAdQAAAK+ci8R
bD64FE1NFAtuJiYEn6pRJAS6LQmVrTFkEgAAaTt0hPEoPhRNEB3qMu8mBNIXKfl3CSgty32CNzcBAAC9
O08VOBSzSqUaBgkpwx4e+6sGIhN8HhtteA90dBIAAI07Tw4QizQ0ZhoJBQVEJpEkzhERC5ELD19flGQ5
NgAAOXJPDosIBxgHf/YFBSssHjJqF6QyBDhUQphGSwE2AAA5IDcOGtsHCBY40FcbM4HXK7yPh24JiBNo
X1B+EicAAGA7OQ4ZYeEIIhNaWn/c8yipKaxdKg0dE90QCkBlAAAAAL765uJne0oVFLS12h3P6xcX0Uli
8hoZGUoCQCcAAAAAOQIY/2cHhhTWNTViBgYNV5ALKrt/RwcHAwF2LgAAAAAAIyV7RfQVIlxcgT4NCwYb
HRoUIhmLBwoDhScAAAAAAAAn/FIHFoMWIhHGcFsNDc15QlTJEBAOAwMjlwAAAAAAAACXJVJmFgqCDC9w
ER0TImhObw6dpwcYWFgAAAAAAAAAAABZXlUPa2uvThFHHCEcRxXIigo9GCVBAAAAAAAAAAAAAAAjO4B1
IDcPYd7s3yHlnUYS1S5ZQQAAAAAAAAAAAAAAAAAwnJwgIDADXqGhRUxGMHYDLvUAAAAAAAAAAAAAAAAA
AAAAciCjcTECVekCOjEwcyMAAAAAAAAAAAAAAAAAAAAAAAAAADpxgIC3dSAg4/4AAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///////wAD//gAAH/gAAA/wAAAP4AAAD8AAAA+AA
AAfgAAAHwAAAA8AAAAOAAAADgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAADwAAAA8AA
AAPgAAAH4AAAB/AAAA/4AAAf/AAAP/4AAH//gAH//+AH//////8oAAAAEAAAACAAAAABAAgAAAAAAEAB
AAAAAAAAAAAAAAABAAAAAQAAAAAAACxQogAtUKIAGAkYABgJGgAcByUAHgckAGpbZwBsXGcAVkRQAFdE
UgAmFyQAJhUmACQqVAAmK1YANScqADMmLAAzO2IAMT1kABolcwAYJnYAFgoaABcKHgAgGkUAJBtGACAz
hAAkMoUAdnaCAHlzgAAnQ4QAKkCHABpCqQAcQq4AEwonABIPJgAZDRgAW05ZAFxMXgCHZlkAhGJcACgW
KAArFS0ANSxLADAuTwApHCQALx4nABtBkQAbSJMAMB0mADUcKwAvYLMAKmW0ACxUlgAlVZkANmuxAD1o
sAAnR54ALkmbABgSOwAeFzwAGw0iABwOIgAeCSYAHQ0lAIiLjQCPj44AGxMXABsQHwBVQlAAU0VWABso
VwAcI14AV0FaAFFHXQBtVGYAMjRSADU0WwA5Jy4ANCovACIXIgAlFyAAIxQlABMlgAAWLIYAIQkgACQP
JwBINkUAQDJLAEc5VgBEO10ASDxfABwXQgAXHUoAO0l0ADVBeQAaNZYAGD+bACIkUgAmLFgAHylkABop
bwAoDiYAKyU1ACohOQAtKj0AEwQbAEAxOwBMOD0AGDeAAB48ggAWNYkAGipxABEneQAhPIwAIhw2ACse
MgAkFzgAKBs6ACQdUgAvbboAdGJwAHFvegBYVFEAU1ZfAFtZWgCQa2YAhm10ACUxYAAoOmYAKzZuAClf
oQBiUl8Ab15cADtEagCnrK8AsKemALSwrgBxcHEAeHZ2AHp4dgB3en4ANiQzADctMwA5LjMANSo9AD4q
OgAxQoEAM0mEADhJgQA8Ro0AY2RlAG1kYABrbW4AVFBgAFhVYwBfX2kAiYGGAIOGiAAkM3AAJTt5AC4/
fgAtbcwAPnPMADl50gBjXXUAJyJEACEjSwAtJ0sALy9NAG9MUgBwUVMAKhQlACUeIgApGSoAOWCuAB8z
dwAcXrMAU09eACJRsAAxW7oAUzhCAJCRjQCVgJ4AkJWXABkRJQBAQGMAUE11AFNScAAqICYANzA4AE5J
SABeRkcAam13AD4wTgA1LloAFVjMACBczAAkaeAARVGOAFhlowCbm6EAn6SnAAAAAACOdJwAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABuasZuMQLfJAAAAAAAARQwDIxVDT718mJ0AAADIKVQo
jZGQao4QD76WhgAAMFV1pSorSxKoj1AsiQAACa10W2FjL2AugGg9BHoAADFzFxgzxcNub21GOhasAJyr
O0efggKzAXDEsGS4QkEIBn80Xbk5ondTIDVsXDyKgz5MuyReUqOhGoE2pnI/ixwFWaQHHhOuMhQfHWJn
vLUAZUh+SZTGlThfspKFVk4AAAp9eBHHN3EZoJO6JU2XAAAAJkpYDXavng6nwUS/AAAAAIe0IiHCy7Za
ZmsniAAAAAAAAFdpC6qpUS2EAAAAAAAAAAAAAMB7mXkAAAAAAAD8A///8AH//8AA///AAf//gAH//4AB
//8AAP//AAD//wAA//8AAP//gAH//4AB///AA///wAP///AP///8P///KAAAADAAAABgAAAAAQAgAAAA
AACAJQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQUFABU1NUBVFQUQtOTU4VTEtOIUpITC5LSEw6S0hMR0xK
TU9NS09WT05PWlBQUV1SUlJhUlJSZFJSUmZTU1NnUlJSZlJSUmRTU1NhUlJSXVJSUldSUlJQU1NTSFNT
Uz9SUlI1UlJSKlFRUSBTU1MVU1NTDFhYWAVAQEABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABoOHQMvJTELNy86IDItOkItJzdoJx8yiSMa
LKIiFyy0IxUrvyUWLcIlGi6/JyIyuC8tOa84Nz6kQ0JGmkpKTJRPT1CRUlJSj1JSUo1TU1OJUlJShFJS
Un5SUlJ2UlJSbVNTU2NSUlJWUlJSR1FRUTlRUVEpUVFRGlVVVQ1FRUUDAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARARgGEQYbFhwPHz4gESF5GQwfshIH
H9sMAx/xCwIb+woAFv0JABf+CgAY/w0AGf8LABn+CgAa/QwDHvsRCSH3FxIl7iAdK+AuLTbPPz9EwkxL
TblRUVGzUlJSrVJSUqhSUlKhU1NTmVNTU45SUlKAUlJScFJSUl5RUVFJUVFRM1JSUhxQUFAJNjY2AQAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdWRzBSgSKBkVAxlMGAsglyES
JtcdCx73FwcZ/hMGGP8NBBb/DQUT/wwDEv8KARH/CgIT/woBFP8MAxP/CwES/w4GGP8VDSD/GBAi/xMM
Hf4PChv8GBQj8yooMuc/P0PaTUxO0VJRUstTUlPFU1NTvlJSUrVSUlKpUlJSm1NTU4hSUlJwUlJSVFNT
UzNVVVUSRUVFAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKeeqQJnVWYQTjdLPioS
KY8cBR3ZJBAm+SwbLf4oFij/Gwod/xUDGP8SAxT/FQgQ/xcKE/8VCBL/FwsW/xUJF/8TBhb/EQUS/xMI
Fv8XDRr/Ihcg/ykcI/8iFiD/GxEe/hsTH/0jHyj4NTE370hER+ZRUFDgUlJS21JSUtVSUlLMUlJSwFJS
UrBSUlKaUlJSe1JSUlBUVFQfPz8/BQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAhHqEA1VF
WR87JTxpKhAowyEFHvQkCCD+KA4k/ykSIv8pFCL/JxIh/yMPIP8kESD/Jhca/ygZHf8oGiH/Kh0l/yca
J/8lFij/IBEj/yITJf8mGCf/KRsj/ywdI/8tHiT/LB0k/ywdJP8rHiX+Jxkj/TElLPlEP0DzUE9O7lJS
UupSUlLkUlJS3FJSUtBSUlK+UlJSoVJSUm5SUlItRUVFCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAB8cnUFU0VQKy0aL4UfBx/eHwYe/R0EHf8eBR3/Iwsh/yUOH/8qEyL/MBso/zMeK/82Ii3/OCUs/zkl
Lv86JzL/OSYx/zUlMv8uIzX/LCI1/zMkN/84KTn/Nyo0/zYpMf82KTD/NSct/zUlLf80JC3/Lh0p/ykb
I/4xJyj8RT06+VBNTPZSUlHyUlJS7VJSUuVSUlLXUlJSvFJSUodSUlI6UlJSCgAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAH5ybwZURUozLx0tlh0IH+geBRz+HgMa/xwDG/8eBx//Ig4k/yYTJ/8nFSj/LBor/zQi
Mf81IzL/PCk3/0QwQP9FL0H/Pyg4/zcfMf8sIDv/NC9G/0E1Q/9CMTz/QDE9/zowOf81LDP/NCkv/zEm
K/8wJCn/MSQq/zImKv8xIyX+NyQj/UU5NvtPTEv4UlJS9FJSUu1SUlLiUlJSylNTU5NTU1NAV1dXCwAA
AAAAAAAAAAAAAAAAAAAAAAAAiHp4BFlKRy40IieYHQgd7RkDIP8ZAh3/HAMc/yEHH/8kDCL/JhUo/ycZ
K/8lFyz/Jhku/zAjNv8yJTj/PC5B/0Y3S/87KUD/NyQ5/zwqPP83Mkr/QkNU/0lBRP9JNTf/Rjg8/0A7
Pf82Mjb/NCsy/zQpL/81Ki3/Nywu/zgrL/81JSv/MBsg/zMeHv5CODT6T01L81JSUutSUlLeUlJSxVJS
Uo9SUlI+VVVVCwAAAAAAAAAAAAAAAAAAAAC0qaoCa1hZIj0oKIokERXqHQkc/xoEHf8bBR3/Hwoj/ygS
Kv8sGC7/KR8x/yQdMv8hGTX/KB8//zQpRP81KUD/NyxD/zcsRf83KEP/QDVT/0Y+Vv81NEb/MzlF/zg7
Pv9EOEH/QzlD/z49Qv89OT//Oi85/zwuNf88LzP/Oi4w/zcrLf8wJCn/KRog/yYVGP8wIB/9RT088lFP
T+BSUlLNUlJSsVJSUnxSUlI1TU1NCQAAAAAAAAAAAAAAAAAAAABnUVUUQyoucSwUGOEhDhT/GwkV/yMK
Gv8oECX/JhMv/ygYNf8qHDv/Jx8//yQgQf8nI0j/LilU/zMpTv85K0n/OC9N/y8rS/82MVH/PDpi/z46
XP8wL0n/KDNO/y9BYP81Q27/JzRo/yEpVf8vKEf/PCw9/z4xN/88MDL/OCwt/y8jI/8iFh7/Gw4a/xwP
Gf8iFR3+Nyot905GRNhSUVGxUlJSj1JSUmBTU1MnQEBABwAAAAAAAAAAAAAAAG9aYAdONTtKLBEXzCgR
Gf0gDhj/IAwY/y0UI/8vGjH/JRk7/yIcQ/8oHUb/JxtF/yYfR/8qJ0z/KipQ/y0oUv86MFT/NzFS/yMo
Tf8fKE7/Ii9T/yswW/8uL1r/JC1c/yU5bv8pR4j/Hj6T/xUtff8gJ1z/My1F/zszPv84MDb/LSQl/yAU
Gf8YCBj/FgUa/xgIG/8cDh//KBkf/T8wLONOSUaeUVFRalNTU0FUVFQZQEBABAAAAAAAAAAAwLe7AWlW
XSA4HiifJw0X+CcTH/8hEB7/JxQj/y8ZLf8oFzX/HhhA/x0cSv8gGUT/Ixg+/ycfQv8qJkf/JidL/yIl
Uf8oJlH/ISJL/xMgTf8RI1D/GS5V/x81b/8eMHf/Fyds/xUqZf8aMnH/GzSC/yA1e/8qNmP/MjVL/zUz
Qf8xLTj/JB8n/x0UH/8bCx7/FwYc/xYEG/8YBx3/HxEa/y4hHfdAOTKuTk1KUFNTUydUVFQNQkJCAQAA
AAAAAAAAXERNCEgvOVwoDRrjJg8d/ycVJf8lGCn/LRww/ysYMP8hFDX/IBpE/xkYSP8TDz7/HBY//yMg
SP8iI0z/HyRR/xwgUv8cHVH/GCZi/xo8gP8ZSZb/I0+g/yJOqf8RQ6v/EEKr/xtKoP8eR5j/HUCL/yU/
d/8vP2H/MTpQ/zEzR/8wLD7/KyQz/yUZLP8dDyP/GAkb/xYGGP8VBRj/Gg4a/yceHv80LiPZR0Q6W1JS
TxdMTEwGAAAAAAAAAACmmJwBYEdRHjAQH6ooCh38LBYn/y4gMP8uIjX/LBw1/yQTMf8hFTj/IBpD/xkV
Qf8aEz7/IxpH/x4fVP8aJWP/IDFy/xglbf8eLXz/KFGp/yNtzf8dcdv/Hmfa/xhQx/8RP6z/Gkeu/xZH
qf8bTaz/IVOn/xxIiv8hO2j/KDJR/yUpSf8rJ0f/LCJA/yIVMv8ZCyP/Fwka/xgIGf8VBhn/FgkZ/yEY
Hv8sJhz3QDwtkU9MQhlGRkUCAAAAAAAAAABiS1AEUDU+USsKG+QwEyX/NSAw/zYpNv82Kjr/Khoz/yUV
M/8lGTv/HhY8/yAWO/8oFzr/JBVB/xUdXP8eQI7/K2C1/yBVtf8nXMv/LnDo/xpz7v8RY9j/FWDQ/w1H
sf8PLIb/HTF5/xoqc/8VKnb/HTiF/yNCif8gOHL/HSpX/x0kTf8kIkr/KCBI/yAWPP8XCin/Fwge/xoK
G/8YCB3/FQgc/xoRHf8kHR3/NTAnzUVBNzRNSUECAAAAAAAAAABtWFwOPyMqky4QHfs3HSv/NyQz/zYp
N/8wJDP/HxQu/x8XOv8iGkL/IRhC/ycaQP8qGT7/HRlL/xw8g/81fMz/N5bt/ymB6/8icvD/IGvz/w9X
4P8MScP/Fla6/xRDnP8WLoL/GCtw/x4lYv8iJGH/ICt0/yU8jf8mQ4r/HTZx/xUmWf8WH0z/ICRR/yEh
Uf8WDzr/Fgko/x0NIf8ZCyD/Egca/xQMGf8fGR7/LSgl8kxEN2pXTj4GAAAAAAAAAACGdHYjOBsfyDYb
JP86IzD/Mh8x/ysbLv8mFyj/FRAv/xIZTP8hJmH/JCNc/yYdTP8nH0f/Hitf/y1krf86lOb/KYno/xpm
2P8maOX/I2bp/w5Jy/8OO7L/MmXA/yBGnP8bNYz/DiZu/xIlav8aKXD/Eyh6/xU0jv8YQ5f/HEmR/xs/
eP8TMGH/FClh/xkkYv8QEUr/EQo0/xkOKP8YCyH/EgcZ/xQMF/8eGhz/KB8e/U09NKNLPjQRAAAAAIl3
egJzX2JJMhYa6joiKP8zHSz/JRIo/yEPKv8kFzP/FRY5/xMgVf8kLHD/JCVk/yEeTv8lIU3/Jzht/yxs
sv8hdMr/HF+7/yFPsP8tWcD/JVvK/w47tf8UPKv/R3PJ/y1Sqv8pT6P/CyBm/w4jav8ULXn/ECyA/xMw
jv8bSa3/KXjP/yd0vP8USY3/EjaB/xgufv8VGVv/FAs4/xQKJ/8XDiP/FQwc/xYPF/8ZFRX/IBMX/0Iw
KNA5LyQqMSwfAWlRVgRgSE1zNRoh+jkgK/8pEyT/Gggg/xwPMP8fHkj/FxxE/xYgUf8bImL/HB5Z/xsk
Wv8fNnj/OV6k/zp5vP8gZK3/IUyR/yxDhf8vTpn/KFKv/xs7qv8vYLn/XovP/zdcsf9Ab8D/CB5z/wwc
Zv8TKHj/EjGM/xo+qf8rYtn/Jon2/xqA3/8RUaz/FUOc/xg7lP8aJ3D/FxNH/xUNLv8ZEST/GxQe/xYQ
Ff8YExP/JBgc/zgqIeo1LiFKMy4gAn5obQdVO0GWPCEq/jEXJv8hCh//Ggch/yAUNv8lIE7/HxpE/xUY
R/8bI2T/JC1w/xcxdP8gT57/NGWu/zFckP8oTXr/NElw/zxIdP8zUZD/L02k/yA7of82c8f/TnnH/0Vs
t/9fldv/ByWG/w8dav8VJHT/Dy2S/yJLyf8lZOr/FXf1/x6F7v8rccj/J1Sl/yVJnf8iOoj/GCdn/xkW
Pf8cESH/IBgd/xkSFP8ZERb/JBgh/ywhH/hUTUFpXVZIA2xRVRFAHyivOBwr/ygMIf8cBB7/Gwgo/yMX
P/8kIVP/HSVV/xsyZv8vS4//KUiR/yFFhP8zWZL/OVB9/z9GX/8+Q1b/REdd/0NMcP84UY3/L0ae/xQx
nf9EgND/Wn/N/0Jyuv9uv+3/DECa/xMnbP8cLHX/HDea/x9Dv/8TQsL/HmHU/zCC3v8nZ7L/KU+S/yVH
kP8cO4f/HzV7/xglXf8TFjr/HBgp/xgRG/8XDBv/IhMk/ycbH/1cVUqFZV9RBGhNUx8yER/ALxEl/yEF
H/8ZAiH/HAsu/x0eRf8eL2D/KUuE/zZpp/8xabD/KFaa/zNRhf87Rmz/Rj5b/0o8Uv8/OVT/PEJs/zlM
iP8uS5f/JEWp/xE3s/9cnOX/WIjP/y1ltf9dsun/DkWZ/xQpc/8dLoL/GDOX/xY1qf8ZQLb/G0mr/xhG
jv8SQHr/IEmG/xQ8h/8LL3//Ey96/xMqcP8PIFT/ExU0/xUKH/8ZCB//IxIn/ycaIP4/OCaYbmlYCGRM
UykpCRbJJwgc/x0BHP8ZAyP/IRAz/x8jR/8pQm//Ol+a/zBgov8jVpz/NFaW/0FKef9GQWD/TkNh/0c8
ZP88N2r/OkSF/zJNpP8mTLX/Ez+6/xxQ1v9ru/n/M3PA/yBYrP8rdsv/CTmc/xQpi/8TJZH/DCmT/x06
nP8rSKf/GC5+/xksZ/8qWJH/PHW9/yNVov8OLXD/FiBd/xwiXP8bIU//FxQ2/xkJJP8aByX/IQ8o/yQV
G/8/NyOihYBwC2NMViwmBhXLIAMW/xkBGv8aBSL/JRYz/y4uUP87TX//LUqC/yJAdP9HXY//WmKP/1FM
Z/9MQkv/S0VU/0NDbv84P3z/M0KF/yI8hv8aO5f/EDex/yZj5/9buPr/GlOm/y9drv89jOH/DEa5/xIv
nv8aMpz/IDaP/zA8dP86Pmf/JC1Z/yxIeP9HhMf/R4fa/ylPk/8aJVX/GhA+/yARO/8qIT3/Jx01/xsL
Kv8ZBSn/Hwol/yYWHP9QRzSik45+C2BJVCQlBhXEHwMZ/xgBHP8aBiP/JhUv/ywlRv8sLl//LTFj/0hI
bv9UU3D/WlVp/1xRW/9YSUr/UEZP/0xMbv84RoD/HjN5/wsdaP8MF23/DRyM/xxV0v9tx/n/Mmq1/zxr
vf9Tq/b/EknE/yI1mf80QIn/LTRw/yspUP8wK0//KD92/zxxsv9DhND/JVOd/yErVf8nHzz/HRI3/x4T
Nf8lHzb/JCAx/xkRKf8bByn/JQwo/yMUGf5ZUUCbkYx9CV1GURYnCRm2HgQb/xgCHv8aByb/JhUy/zAf
OP86KUP/VENf/2pVa/9hS1f/ZlJU/3ReX/9yW2H/YlJi/1FTdf8tQX7/Dyp4/wkcbf8ZG2r/HRl6/w8w
qv9gq+3/PXbB/zNuxP8+m/H/Dju2/yUqgv8mLGj/Jido/x8ja/8iMX7/LVir/zV90f8zc8H/IDt0/yIf
PP8lHzn/IR5B/yIePv8eHDH/HB4q/xkWH/8hDx7/IRAd/x0UD/1pYlSKdnBgBXRibAk/KDeeHAMc/hcD
If8dCCf/KRU1/zMiPv9GNU//aVpy/3tqff9wXmr/bFpe/3JdXP93YWL/Zlpp/1BZf/8nRYv/Dyx//w0d
bf8QF2P/GxVr/xIpkv9Sjd3/N2a3/zl0wf84ieP/FDio/x8kcf8VHmf/HzKE/xw9mv8ROqL/F06x/yt2
yf8/fsL/LEZ0/yEkRf8hKUz/KDBV/yUkSP8aFDD/Hxon/yYcI/8lFx7/IBgZ/yMbEPpwZVhyf3RnBFhI
VAROPUx+FwMd+xQCIv8cBSH/KBAs/zAkR/9EP2H/VVR3/1ldgv9cXnr/ZFtr/3NeY/9zXWH/X1lt/0VU
hP8dPIz/ECqG/xMgdf8QGGj/HB9t/yQ9jv9Gdcb/OWew/ytepP81bcT/GT2c/xchb/8SHWz/GzOM/xtC
qP8RPrP/Ik66/yBInP8YMnX/HiVX/yQoVv8iLl3/JjBZ/yMhRf8iFjH/MiQz/zIhLv8qHSf/IyEg/ysj
Fe+KgHVTpZuRAm1cZwJbSVdVGAMa7xICHv8YAh7/Hggl/ysgRP9APmX/SlB7/01Yiv9VWHn/amBt/31n
bf9oWWr/QkZt/yo6dv8pQY7/K0Wb/xwzhP8fMXr/OkiJ/zxSmP9DabH/Q26o/0VppP9PesP/Fz2V/xUi
dv8VJ3D/Fix+/xAwj/8aQav/MFK4/x80hP8eIVz/Ly5i/zI1bv8qLmb/JSNS/yQcPf83KT7/RTRC/zQl
Mv8yKDT/KSYk/z0vINiViYAyvrSuAaCUmgF0Y20tIAgb0xgCG/8gAh7/JQom/zIeP/8/Nlz/SUh1/1dW
gf9qXXH/hHJw/4Jvbv9aUGX/Njlm/y00bv8yP3//L0WJ/y1Dgv8+Tob/SlSM/0NNlf9FV6L/PFiU/0Vr
qv8wX63/DSyH/xkpif8cMo//HjiQ/wwwiv8ZSaL/KlGr/xw0hv8nNXD/Lz9w/yQ7bf8pPG7/MjVg/zov
TP9TQlP/QTA+/yYaK/8yKjf/MiYi/llHNLCViHsWAAAAAAAAAABtW2QSNBsqoh0EGv0mCCL/Nhcv/0Qo
QP9VPVj/Z1Ry/3xhef+ScXL/mH1x/3xoZv9PQlb/My1T/ygqXP8vPHb/PVKL/0pakP9JU43/RkqF/0dE
h/9FRY7/MkaK/0ZxvP8YQ6D/DRuB/x0tk/8YNaH/HT6s/xNArf8eWbz/KFm1/yFBlf8zRIP/NEBy/yo/
a/85TnP/RUxp/1VKXv9YQ07/MiAs/yMZKv8zLDf/Oy4n925gUHh/cF4IAAAAAAAAAABfS1QGTTZDYiEF
HO4sEir/PyIy/1AuOv92VmD/jG11/5lzdv+jfXT/iXBq/1pIV/88L0z/NDZY/z1Nef9IY5r/VG6l/1hn
o/9LU5v/O0KK/zIyd/83NYH/L0GP/0hswP8TMZL/Fh99/xgug/8ONY//Hkap/ydXwf8wZsn/NmC2/zNN
mv9DT4r/Skp4/0dFbP9LSmn/VlBm/2FQXf9MMzv/KxUd/yYZJP81Ky7/TD0w2Il8bj+uo5gDAAAAAAAA
AACOfYIBWEFOKScLIb0rESn+Ox0q/2A+Qf+WdG//o4J5/518eP+NdXP/XlNg/zQwUv8rLlj/Ok54/1Bs
of9YdLP/X3Wz/1ZwtP9LbLz/Nlmq/yM2hP8kK37/Kj2T/ydBm/8RJ4D/Iix5/x8ud/8TNX7/LlOd/zVh
r/8oVKH/MEuR/z1Niv9QVYX/WU5z/1xMaP9nV27/ZFRl/1Q/Sf87Iif/JQ8V/yocIf89LyX6Z1RAmpKB
bxcAAAAAAAAAAAAAAAAAAAAAUkFQCzonOXEkCyLtQyIw/3xWU/+mfnX/o354/4xvc/91ZXP/VlBt/zk8
ZP8pN2H/OEx7/1Jgn/9gZa7/Y3C0/1WCxP9Ii9T/J2q+/xpDk/8dMoH/K0Wc/xUuiP8dL37/KS91/yox
c/8rPHv/PFKM/zRSi/8qRX7/PEl+/0tSgP9QTnX/XVBr/29gb/9sXWv/UEFP/zwqNv8zICf/KBge/zIk
Jv9QPzHbf21YT5yJcwYAAAAAAAAAAAAAAAAAAAAAmpedAllLWCsxGCizTCox/IdhV/+edGj/j2tu/3Rd
bv9lWHT/WVR0/zc4Wv8lKk3/P0Rs/1xajv9WU5T/SVSU/0NinP8wWpf/F0SK/xI4gP8aOob/K0+j/x4/
k/8lOYb/KTJ7/y42dP86QXf/Qkl8/zpEdP8xOGb/Nzhj/z8+ZP9PSGr/YVJu/19PY/9KOkr/Py4+/0My
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
AAAP//////wAAD///////4AB/////ygAAAAgAAAAQAAAAAEAIAAAAAAAgBAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE1LTwhBPUUeODM/OzQt
Olc1LTtpOTA+dTw4QXdFREh2TExOdFFRUnRTU1JzUlJScFJSUmpSUlJiUlJSVVNTU0dSUlI2UVFRJFJS
UhNVVVUGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFAEYAREFGgwdECA1HQ8iexUK
IrQQCCHUDwUb5BAFHOoSBR7sEQgf6RYPJeMfGivXLCo1xkFBRbROTk+qUlJSolJSUppSUlKNUlJSfVJS
UmdRUVFNUVFRMFJSUhJHR0cCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH1tewokDSREGwshrCUV
KOoaCRv+EQQX/w4EE/8OBBH/DQMS/w0DFP8MAhL/EAcY/xkRIf8ZEB7+FxEf+SckLuxDQkXbUVBR0lNT
U8hSUlK8UlJSqVJSUo1SUlJnU1NTL1BQUAgAAAAAAAAAAAAAAAAAAAAAAAAAAIR6hAFVRVkeMRgvkiIG
H+EmDST8KhUl/iURIf8fDB7/IREZ/yMVG/8kFyD/IhQj/x0PIP8fESH/JRgj/yscIv8oGyP+KBwj/ike
J/o6MTbzUE9O6lJSUuNSUlLXUlJSwlJSUp9SUlJTTk5OEQAAAAAAAAAAAAAAAAAAAAAAAAAAT0FMMyMO
JLUfBR38HQQc/yIKIf8mECL/Lhkn/zUhLf84JC7/PCgz/z0pNv8yIjL/LCI2/zcpOv86Kzj/Nysz/zUo
L/80JSz/Lx8q/ywfJf49Mi/7UExL9lJSUvBSUlLkUlJSyFJSUnJTU1MZAAAAAAAAAAAAAAAAh3l4AVVG
QjYjDyDKGQQf/BwCG/4gBh7/JBEl/yYXK/8nGC3/MSM1/zkqPP9EM0f/OiU6/zgoPf89Ok//SDtA/0U2
O/87Njr/NCwx/zMoLf81Kiz/Nyou/jIeI/46KSf8TkxK9VJSUulSUlLOUlJSeFNTUxoAAAAAAAAAAAAA
AABsWlsgMRsbuR0KGPwcBBv/IAsk/yoVLf8pHjP/Ihw1/ycgQv81KUX/NipD/zYrRf9ANFP/QDtS/zE1
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
///AA///4Af///AP//8=
</value>
</data>
</root>

View File

@@ -0,0 +1,106 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ChamChat
{
public static class Clients
{
public static List<Client> GetAll()
{
List<Client> result = new List<Client>();
Client client00018 = new HTS7057_Client(18, Models.ClientType.HTS7057);
client00018.Address = 1;
result.Add(client00018);
Client client00847 = new TSx_Client(847, Models.ClientType.TSE11A);
client00847.Address = 1;
result.Add(client00847);
Client client00947 = new TSx_Client(947, Models.ClientType.TSE11A);
client00947.Address = 2;
result.Add(client00947);
Client client00987 = new TSx_Client(987, Models.ClientType.TSE11A);
client00987.Address = 3;
result.Add(client00987);
Client client01728 = new TSx_Client(1728, Models.ClientType.TSD100);
client01728.Address = 4;
result.Add(client01728);
Client client01880 = new TSx_Client(1880, Models.ClientType.TSE11A);
client01880.Address = 5;
result.Add(client01880);
Client client00781 = new LHL113_Client(781, Models.ClientType.LHL113);
client00781.Address = 6;
result.Add(client00781);
Client client00782 = new LHL113_Client(782, Models.ClientType.LHL113);
client00782.Address = 7;
result.Add(client00782);
Client client00986 = new PLxKPH_Client(986, Models.ClientType.PL3KPH);
client00986.Address = 8;
result.Add(client00986);
Client client01056 = new PLxKPH_Client(1056, Models.ClientType.PL2KPH);
client01056.Address = 9;
result.Add(client01056);
Client client01120 = new PLxKPH_Client(1120, Models.ClientType.PL3KPH);
client01120.Address = 10;
result.Add(client01120);
//Client client00995 = new Client(995, null);
//client00995.Address = 11;
//result.Add(client00995);
//Client client01238 = new Client(1238, null);
//client01238.Address = 12;
//result.Add(client01238);
//Client client02183 = new Client(2183, null);
//client02183.Address = 13;
//result.Add(client02183);
Client client02222 = new TSx_Client(2222, Models.ClientType.TSD100S);
client02222.Address = 14;
result.Add(client02222);
Client client00038 = new Watlow988U_Client(38, Models.ClientType.Despatch_Watlow988U);
client00038.Address = 1;
result.Add(client00038);
return OrderByMIDS(result);
}
private static List<Client> OrderByMIDS(List<Client> list)
{
List<Client> result = new List<Client>();
while (list.Count > 0)
{
int k = 0;
for (int i = 0; i < list.Count; i++)
{
if (list[i].MIDS < list[k].MIDS)
k = i;
}
result.Add(list[k]);
list.RemoveAt(k);
}
return result;
}
}
}

327
ChamChat/ChamChat/Graph.cs Normal file
View File

@@ -0,0 +1,327 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using ChamChat.Models;
namespace ChamChat
{
public class Graph
{
// Rule: Max size of image is limietd by Control.Location as 2^15 = 32768 pix.
private const float _MaxSizeOfImage = 32768F;
public Int32 MaxSizeOfImage { get { return (int)Math.Round(_MaxSizeOfImage); } }
public Graph(Profile Profile, Size SizeOfView, Client Client)
{
_Profile = Profile;
_SizeOfView = SizeOfView;
_Client = Client;
_Width = _SizeOfView.Width;
_Height = _SizeOfView.Height;
_HrsInView = 24;
// Pens
_Pen = new Pen(Color.Black, 3); ;
_PenTemp = new Pen(Color.Red, 3); ;
_PenRH = new Pen(Color.Blue, 3); ;
_PenPreTemp = new Pen(Color.Tomato, 1);
_PenPreTemp.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
_PenLoopBox = new Pen(Color.Green, 2);
_PenLoopBox.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
_PenStepBorder = new Pen(Color.LightGray, 1); ;
_PenStepBorder.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
_Font = new Font("Arial", 8);
_MarginY = (float)Math.Round(_Height * 0.07);
_MarginX = Math.Min(20,(float)Math.Round(_Width * 0.05));
}
private float _MarginY = 20;
private float _MarginX = 20;
private Size _SizeOfView;
private Font _Font;
private Pen _PenStepBorder;
private Pen _PenPreTemp;
private Pen _PenTemp;
private Pen _PenRH;
private Pen _Pen;
private Pen _PenLoopBox;
private Client _Client; public Client Client { get { return _Client; } }
private Profile _Profile; public Profile Profile { get { return _Profile; } }
private Bitmap _Image;
private double _maxY = double.MinValue;
private double _minY = double.MaxValue;
private float _HrsInView = 24; public float HrsInView { get { return _HrsInView; } set { _HrsInView = value; } }
private double _maxX = 6; // in minutes
private float _Height; public Int32 Height { get { return (int)Math.Round(_Height); } set { _Height = value; } }
private float _Width; public Int32 Width { get { return (int)Math.Round(_Width); } }
private float _maxStepDisplayDuration = 240; public Double MaxStepDisplayDuration { set { _maxStepDisplayDuration = (float)value; } }
float[,] _StepBorders; // Set while drawing
private void SetScale()
{
_Width = _SizeOfView.Width;
_minY = Double.MaxValue;
_maxY = Double.MinValue;
_maxX = 0;
foreach (Step s in _Profile.Steps)
{
// Temperature
_minY = Math.Min(_minY, s.T);
_maxY = Math.Max(_maxY, s.T);
if (_Client.Parameters.Contains(Parameter.PreTemp))
{
_maxY = Math.Max(_maxY, s.PreTemp);
_minY = Math.Min(_minY, s.PreTemp);
}
// Shorten if steps are displayed cropped
if (s.DurationMin > _maxStepDisplayDuration)
_maxX += _maxStepDisplayDuration;
else
_maxX += s.DurationMin;
}
// Take a margin
_maxY += Math.Abs(0.15 * _maxY);
_minY -= Math.Abs(0.07 * _minY);
// Max number of hours in 1 view
float pixelsPerMinute = _SizeOfView.Width / (60 * _HrsInView);
_Width = (float)Math.Round(pixelsPerMinute * (float)_maxX);
_Width = Math.Min(_MaxSizeOfImage, _Width);
_Width = Math.Max(_SizeOfView.Width, _Width);
_maxY = Math.Max(100, _maxY); // Scale is 100 minimum (for RH)
}
private float YtoCanvas(Double y)
{
float a = (_Height - 2 * _MarginY) / ((float)_minY - (float)_maxY);
float b = _MarginY - a * (float)_maxY;
return a * (float)y + b;
}
private float XtoCanvas(Double x)
{
float a = ((float)_Width - 2 * _MarginX) / (float)_maxX;
float b = _MarginX;
return a * (float)x + b;
}
private void Create()
{
_Image = new Bitmap((int)_Width, (int)_Height);
Graphics g = Graphics.FromImage(_Image);
g.Clear(Color.White);
// Horizontal axis
g.DrawLine(_Pen, 0, YtoCanvas(0), _Width, YtoCanvas(0));
// Temperature
float X1 = 0;
float X2 = 0;
double T1 = 25;
double T2 = 0;
double RH1 = 50;
double RH2 = 50;
_StepBorders = new float[_Profile.Steps.Count, 2];
g.DrawLine(_PenStepBorder, XtoCanvas(X1), 0, XtoCanvas(X1), _Height);
// Draw from room temperature of 25 °C to first start
g.DrawLine(_PenTemp, XtoCanvas(X1), YtoCanvas(T1), XtoCanvas(X2), YtoCanvas(_Profile.Steps[0].T));
for (int i = 0; i < _Profile.Steps.Count; i++)
{
Step s = _Profile.Steps[i];
T2 = s.T;
RH2 = s.RH;
X2 = X1 + (float)s.DurationMin;
// Draw the connecting vertical line (infinite ramp)
if (!s.RampCtrlT)
{
g.DrawLine(_PenTemp, XtoCanvas(X1), YtoCanvas(T1), XtoCanvas(X1), YtoCanvas(T2));
T1 = s.T;
}
if (!s.RampCtrlRH && s.RH > 0)
{
g.DrawLine(_PenRH, XtoCanvas(X1), YtoCanvas(RH1), XtoCanvas(X1), YtoCanvas(RH2));
RH1 = s.RH;
}
// Draw the profile line
if (s.DurationMin > _maxStepDisplayDuration)
{
// Shrink period with dotted line
X2 = X1 + _maxStepDisplayDuration;
if (RH2 > 0)
{
if (s.RampCtrlRH) // Draw RH ramp with dots in the middle
{
float x1 = XtoCanvas(X1); float x2 = XtoCanvas(X2);
float y1 = YtoCanvas(RH1); float y2 = YtoCanvas(RH2);
PointF P1 = new PointF(x1, y1);
PointF P2 = new PointF(x1 + 0.25F * (x2 - x1), y1 + 0.25F * (y2 - y1));
PointF P3 = new PointF(x1 + 0.75F * (x2 - x1), y1 + 0.75F * (y2 - y1));
PointF P4 = new PointF(x2, y2);
g.DrawLine(_PenRH, P1, P2);
_PenRH.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
g.DrawLine(_PenRH, P2, P3);
_PenRH.DashStyle = System.Drawing.Drawing2D.DashStyle.Solid;
g.DrawLine(_PenRH, P3, P4);
}
else // Draw straight RH line with dots in the middle
{
g.DrawLine(_PenRH, XtoCanvas(X1), YtoCanvas(RH1), XtoCanvas(X1 + 0.25 * _maxStepDisplayDuration), YtoCanvas(RH2));
_PenRH.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
g.DrawLine(_PenRH, XtoCanvas(X1 + 0.25 * _maxStepDisplayDuration), YtoCanvas(RH1), XtoCanvas(X1 + 0.75 * _maxStepDisplayDuration), YtoCanvas(RH2));
_PenRH.DashStyle = System.Drawing.Drawing2D.DashStyle.Solid;
g.DrawLine(_PenRH, XtoCanvas(X1 + 0.75 * _maxStepDisplayDuration), YtoCanvas(RH1), XtoCanvas(X2), YtoCanvas(RH2));
}
}
if (s.RampCtrlT) // Draw T ramp with dots in the middle
{
float x1 = XtoCanvas(X1); float x2 = XtoCanvas(X2);
float y1 = YtoCanvas(T1); float y2 = YtoCanvas(T2);
PointF P1 = new PointF(x1, y1);
PointF P2 = new PointF(x1 + 0.25F * (x2 - x1), y1 + 0.25F * (y2 - y1));
PointF P3 = new PointF(x1 + 0.75F * (x2 - x1), y1 + 0.75F * (y2 - y1));
PointF P4 = new PointF(x2, y2);
g.DrawLine(_PenTemp, P1, P2);
_PenTemp.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
g.DrawLine(_PenTemp, P2, P3);
_PenTemp.DashStyle = System.Drawing.Drawing2D.DashStyle.Solid;
g.DrawLine(_PenTemp, P3, P4);
}
else // Draw straight T line with dots in the middle
{
g.DrawLine(_PenTemp, XtoCanvas(X1), YtoCanvas(T1), XtoCanvas(X1 + 0.25 * _maxStepDisplayDuration), YtoCanvas(T2));
_PenTemp.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
g.DrawLine(_PenTemp, XtoCanvas(X1 + 0.25 * _maxStepDisplayDuration), YtoCanvas(T1), XtoCanvas(X1 + 0.75 * _maxStepDisplayDuration), YtoCanvas(T2));
_PenTemp.DashStyle = System.Drawing.Drawing2D.DashStyle.Solid;
g.DrawLine(_PenTemp, XtoCanvas(X1 + 0.75 * _maxStepDisplayDuration), YtoCanvas(T1), XtoCanvas(X2), YtoCanvas(T2));
}
}
else // Period is shorter than _maxStepDisplayDuration
{
if (RH2 > 0)
{
if (RH2 == T2)
g.DrawLine(_PenRH, XtoCanvas(X1), YtoCanvas(RH1) + _PenRH.Width / 2, XtoCanvas(X2), YtoCanvas(RH2) + _PenRH.Width / 2);
else
g.DrawLine(_PenRH, XtoCanvas(X1), YtoCanvas(RH1), XtoCanvas(X2), YtoCanvas(RH2));
}
if (T2 == RH2)
g.DrawLine(_PenTemp, XtoCanvas(X1), YtoCanvas(T1) - _PenTemp.Width / 2, XtoCanvas(X2), YtoCanvas(T2) - _PenTemp.Width / 2);
else
g.DrawLine(_PenTemp, XtoCanvas(X1), YtoCanvas(T1), XtoCanvas(X2), YtoCanvas(T2));
}
// Draw temperature text (below if RH > T or if T < 0)
if (!s.RampCtrlT)
{
string sTemp = String.Format("{0:0}", s.T);
if (s.T <= 0 || RH2 > T2)
g.DrawString(sTemp, _Font, new SolidBrush(_PenTemp.Color), new PointF(XtoCanvas(X1) + 2, YtoCanvas(s.T) + 2));
else
g.DrawString(sTemp, _Font, new SolidBrush(_PenTemp.Color), new PointF(XtoCanvas(X1) + 2, YtoCanvas(s.T) - g.MeasureString(sTemp, _Font).Height - 2));
}
// Draw RH text (always below line)
if (!s.RampCtrlRH && s.RH > 0)
{
string sRH = String.Format("{0:0}", s.RH);
g.DrawString(sRH, _Font, new SolidBrush(_PenRH.Color), new PointF(XtoCanvas(X1) + 2, YtoCanvas(s.RH) + 2));
}
// Draw pre-temp
if (_Client.Parameters.Contains(Parameter.PreTemp))
g.DrawLine(_PenPreTemp, XtoCanvas(X1), YtoCanvas(s.PreTemp), XtoCanvas(X2), YtoCanvas(s.PreTemp));
// Draw step border
string stepInfo = String.Format("{0:00}", s.PK + 1);
g.DrawLine(_PenStepBorder, XtoCanvas(X2), 0, XtoCanvas(X2), _Height);
float h = g.MeasureString(stepInfo, _Font).Height;
float w = g.MeasureString(stepInfo, _Font).Width;
if (w < XtoCanvas(X2) - XtoCanvas(X1))
g.DrawString(stepInfo, _Font, Brushes.Black, new PointF(XtoCanvas(X1) + 2, _Height - h - 2));
// Add to stepBorders
_StepBorders[i, 0] = X1;
_StepBorders[i, 1] = X2;
T1 = T2;
RH1 = RH2;
X1 = X2;
}
// Loops boxes
foreach (Loop loop in _Profile.Loops)
{
float xLeft = _StepBorders[loop.First, 0];
float xRight = _StepBorders[loop.Last, 1];
g.DrawRectangle(_PenLoopBox, XtoCanvas(xLeft) + 3, _MarginY, XtoCanvas(xRight) - XtoCanvas(xLeft) - 6, _Height - 2 * _MarginY);
string l = string.Format("{0:0}X", loop.N);
g.DrawString(l, _Font, new SolidBrush(_PenLoopBox.Color), new PointF(XtoCanvas(xLeft) + 6, _MarginY));
}
//g.DrawString(_Width.ToString(), _Font, Brushes.Black, new PointF(0, 0));
g.Dispose();
}
public Bitmap GetImage()
{
SetScale();
Create();
return _Image;
}
public Int32 StepAtMousePosition(Int32 X)
{
for (int i = 0; i < _StepBorders.GetLength(0); i++)
if (X > XtoCanvas(_StepBorders[i, 0]) && X < XtoCanvas(_StepBorders[i, 1]))
return i;
return -1;
}
}
}

View File

@@ -0,0 +1,375 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FTD2XX_NET;
using ChamChat.Models;
namespace ChamChat
{
// Communication with FDTI USB-COM422 Plus 1 or WE
public class FDTI_USB_RS232 : Interface
{
public FDTI_USB_RS232(String ID) : base(ID)
{
_Type = InterfaceType.FDTI_USB_RS232;
}
public FDTI_USB_RS232()
: base()
{
_Type = InterfaceType.FDTI_USB_RS232;
}
// Properties and fields
private static FTDI _RS232COM = new FTDI();
private static uint _Baudrate = 9600;
private static FlowControl _FlowControl = FlowControl.FT_FLOW_NONE;
private System.Object lockDataTransfer = new System.Object();
private bool _Connected = false; public Boolean Connected { get { return _Connected; } }
public override Boolean Open()
{
bool result;
if (_ID != null)
result = OpenByID();
else
result = OpenSingleConnected();
return result;
}
public override Boolean Close()
{
_RS232COM.Close();
_Connected = false;
_RS232COM = null;
return true;
}
private Boolean OpenByID()
{
_InterfaceStatus = null;
UInt32 ftdiDeviceCount = 0;
FTDI.FT_STATUS ftStatus = FTDI.FT_STATUS.FT_OK;
// Determine the number of FTDI devices connected to the machine
ftStatus = _RS232COM.GetNumberOfDevices(ref ftdiDeviceCount);
// Check status
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to get number of FTDI devices", ftStatus.ToString());
return false;
}
// If no devices available, return
if (ftdiDeviceCount == 0)
{
_InterfaceStatus = new InterfaceStatus("No FTDI devices found");
return false;
}
// Allocate storage for device info list
FTDI.FT_DEVICE_INFO_NODE[] ftdiDeviceList = new FTDI.FT_DEVICE_INFO_NODE[ftdiDeviceCount];
// Populate our device list
ftStatus = _RS232COM.GetDeviceList(ftdiDeviceList);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to get FTDI devices", ftStatus.ToString());
return false;
}
// Find all USB-COM422 devices
List<FTDI.FT_DEVICE_INFO_NODE> ftdiDevices = new List<FTDI.FT_DEVICE_INFO_NODE>();
for (UInt32 i = 0; i < ftdiDeviceCount; i++)
ftdiDevices.Add(ftdiDeviceList[i]);
List<FTDI.FT_DEVICE_INFO_NODE> USBCOM232List = ftdiDevices.FindAll(delegate(FTDI.FT_DEVICE_INFO_NODE node) { return node.SerialNumber == _ID; });
if (USBCOM232List.Count > 1)
{
_InterfaceStatus = new InterfaceStatus("More than one USB-COM232 devices with given serial number found");
return false;
}
if (USBCOM232List.Count == 0)
{
_InterfaceStatus = new InterfaceStatus("No USB-COM232 device found with given serial number");
return false;
}
// Open device by serial number
ftStatus = _RS232COM.OpenBySerialNumber(USBCOM232List[0].SerialNumber);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to open USB-COM232 device", ftStatus.ToString());
return false;
}
_ID = USBCOM232List[0].SerialNumber;
// Set up device data parameters
// Set Baud rate
ftStatus = _RS232COM.SetBaudRate(_Baudrate);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to set baud rate in USB-COM232 device", ftStatus.ToString());
return false;
}
// Set data characteristics - Data bits, Stop bits, Parity
ftStatus = _RS232COM.SetDataCharacteristics(FTDI.FT_DATA_BITS.FT_BITS_8, FTDI.FT_STOP_BITS.FT_STOP_BITS_1, FTDI.FT_PARITY.FT_PARITY_NONE);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to set data characteristics in USB-COM232 device", ftStatus.ToString());
return false;
}
// Set flow control - set Xon/Xoff control OFF
ushort flowCtrl = (ushort)_FlowControl;
ftStatus = _RS232COM.SetFlowControl(flowCtrl, 0x11, 0x13);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to set flow control in USB-COM232 device", ftStatus.ToString());
return false;
}
// Set read timeout to 5 seconds, write timeout to infinite
ftStatus = _RS232COM.SetTimeouts(5000, 0);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to set timeouts in USB-COM232 device", ftStatus.ToString());
return false;
}
_Connected = true;
return true;
}
private Boolean OpenSingleConnected()
{
_InterfaceStatus = null;
UInt32 ftdiDeviceCount = 0;
FTDI.FT_STATUS ftStatus = FTDI.FT_STATUS.FT_OK;
// Determine the number of FTDI devices connected to the machine
ftStatus = _RS232COM.GetNumberOfDevices(ref ftdiDeviceCount);
// Check status
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to get number of FTDI devices",ftStatus.ToString());
return false;
}
// If no devices available, return
if (ftdiDeviceCount == 0)
{
_InterfaceStatus = new InterfaceStatus("No FTDI devices found");
return false;
}
// Allocate storage for device info list
FTDI.FT_DEVICE_INFO_NODE[] ftdiDeviceList = new FTDI.FT_DEVICE_INFO_NODE[ftdiDeviceCount];
// Populate our device list
ftStatus = _RS232COM.GetDeviceList(ftdiDeviceList);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to get FTDI devices", ftStatus.ToString());
return false;
}
// Find all USB-COM422 devices
List<FTDI.FT_DEVICE_INFO_NODE> ftdiDevices = new List<FTDI.FT_DEVICE_INFO_NODE>();
for (UInt32 i = 0; i < ftdiDeviceCount; i++)
ftdiDevices.Add(ftdiDeviceList[i]);
List<FTDI.FT_DEVICE_INFO_NODE> USBCOM232List = ftdiDevices.FindAll(delegate(FTDI.FT_DEVICE_INFO_NODE node) { return (node.Description.ToString().Contains("FTDI_USB_RS232")); });
if (USBCOM232List.Count > 1)
{
_InterfaceStatus = new InterfaceStatus("More than one USB-COM232 device found");
return false;
}
if (USBCOM232List.Count == 0 )
{
_InterfaceStatus = new InterfaceStatus("No USB-COM232 device found");
return false;
}
// Open device by serial number
ftStatus = _RS232COM.OpenBySerialNumber(USBCOM232List[0].SerialNumber);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to open USB-COM232 device", ftStatus.ToString());
return false;
}
_ID = USBCOM232List[0].SerialNumber;
// Set up device data parameters
// Set Baud rate
ftStatus = _RS232COM.SetBaudRate(_Baudrate);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to set baud rate in USB-COM232 device", ftStatus.ToString());
return false;
}
// Set data characteristics - Data bits, Stop bits, Parity
ftStatus = _RS232COM.SetDataCharacteristics(FTDI.FT_DATA_BITS.FT_BITS_8, FTDI.FT_STOP_BITS.FT_STOP_BITS_1, FTDI.FT_PARITY.FT_PARITY_NONE);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to set data characteristics in USB-COM232 device", ftStatus.ToString());
return false;
}
// Set flow control - set Xon/Xoff control OFF
ushort flowCtrl = (ushort)_FlowControl;
ftStatus = _RS232COM.SetFlowControl(flowCtrl, 0x11, 0x13);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to set flow control in USB-COM232 device", ftStatus.ToString());
return false;
}
// Set read timeout to 5 seconds, write timeout to infinite
ftStatus = _RS232COM.SetTimeouts(5000, 0);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to set timeouts in USB-COM232 device", ftStatus.ToString());
return false;
}
_Connected = true;
return true;
}
private string ReplaceDelimeters(string cmd)
{
string result = cmd;
result = result.Replace(((char)13).ToString(), "<CR>");
result = result.Replace(((char)10).ToString(), "<LF>");
return result;
}
public override DataTransferLog DataTransfer(String Command, out String _ReturnData, Int32 ReturnDataWaitms)
{
lock (lockDataTransfer) // Calling threads will wait for the current thread to finish executing the locked section.
{
DataTransferLog dataTransferLog = new DataTransferLog(ReplaceDelimeters(Command), "", this);
_ReturnData = "";
_InterfaceStatus = null;
// Construct string to send
string dataToSend = Command.Replace(" ", "");
FTDI.FT_STATUS ftStatus = FTDI.FT_STATUS.FT_OK;
UInt32 numBytesWritten = 0;
ftStatus = _RS232COM.Write(dataToSend, dataToSend.Length, ref numBytesWritten);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to write to USB-COM232 device", ftStatus.ToString());
_ReturnData = "Failed to write to USB-COM232 device | " + ftStatus.ToString();
dataTransferLog.ReturnData = _ReturnData;
return dataTransferLog;
}
// Read from devices
if (ReturnDataWaitms > 0)
{
System.Threading.Thread.Sleep(ReturnDataWaitms);
UInt32 numBytesAvailable = 0;
ftStatus = _RS232COM.GetRxBytesAvailable(ref numBytesAvailable);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to get number of bytes available to read from USB-COM232 device", ftStatus.ToString());
dataTransferLog.ReturnData = "Failed to get number of bytes available to read from USB-COM232 device | " + ftStatus.ToString();
return dataTransferLog;
}
// Now that we have the amount of data we want available, read it
string readData;
UInt32 numBytesRead = 0;
// Note that the Read method is overloaded, so can read string or byte array data
ftStatus = _RS232COM.Read(out readData, numBytesAvailable, ref numBytesRead);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to read data from USB-COM232 device", ftStatus.ToString());
dataTransferLog.ReturnData = "Failed to read data from USB-COM232 device | " + ftStatus.ToString();
return dataTransferLog;
}
_ReturnData = readData.Trim();
dataTransferLog.ReturnData = _ReturnData;
}
else
{
_ReturnData += "not requested";
dataTransferLog.ReturnData = _ReturnData;
}
return dataTransferLog;
} // End lock
}
public override string ToString()
{
return string.Format("{0}.{1}: Baud {2:0}, Flowcontrol {3}", _Type, _ID, _Baudrate, _FlowControl.ToString());
}
}
}

View File

@@ -0,0 +1,378 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FTD2XX_NET;
using ChamChat.Models;
namespace ChamChat
{
// Communication with FDTI USB-COM422 Plus 1 or WE
public class FDTI_USB_COM422 : Interface
{
public FDTI_USB_COM422(String ID) : base(ID)
{
_Type = InterfaceType.FDTI_USB_COM422;
}
public FDTI_USB_COM422()
: base()
{
_Type = InterfaceType.FDTI_USB_COM422;
}
// Properties and fields
private static FTDI _RS422COM = new FTDI();
private static uint _Baudrate = 9600;
private static FlowControl _FlowControl = FlowControl.FT_FLOW_NONE;
private System.Object lockDataTransfer = new System.Object();
private bool _Connected = false; public Boolean Connected { get { return _Connected; } }
public override Boolean Open()
{
bool result;
if (_ID != null)
result = OpenByID();
else
result = OpenSingleConnected();
return result;
}
public override Boolean Close()
{
_RS422COM.Close();
_Connected = false;
_RS422COM = null;
return true;
}
private Boolean OpenByID()
{
_InterfaceStatus = null;
UInt32 ftdiDeviceCount = 0;
FTDI.FT_STATUS ftStatus = FTDI.FT_STATUS.FT_OK;
// Determine the number of FTDI devices connected to the machine
ftStatus = _RS422COM.GetNumberOfDevices(ref ftdiDeviceCount);
// Check status
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to get number of FTDI devices", ftStatus.ToString());
return false;
}
// If no devices available, return
if (ftdiDeviceCount == 0)
{
_InterfaceStatus = new InterfaceStatus("No FTDI devices found");
return false;
}
// Allocate storage for device info list
FTDI.FT_DEVICE_INFO_NODE[] ftdiDeviceList = new FTDI.FT_DEVICE_INFO_NODE[ftdiDeviceCount];
// Populate our device list
ftStatus = _RS422COM.GetDeviceList(ftdiDeviceList);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to get FTDI devices", ftStatus.ToString());
return false;
}
// Find all USB-COM422 devices
List<FTDI.FT_DEVICE_INFO_NODE> ftdiDevices = new List<FTDI.FT_DEVICE_INFO_NODE>();
for (UInt32 i = 0; i < ftdiDeviceCount; i++)
ftdiDevices.Add(ftdiDeviceList[i]);
List<FTDI.FT_DEVICE_INFO_NODE> USBCOM422List = ftdiDevices.FindAll(delegate(FTDI.FT_DEVICE_INFO_NODE node) { return node.SerialNumber == _ID; });
if (USBCOM422List.Count > 1)
{
_InterfaceStatus = new InterfaceStatus("More than one USB-COM422 devices with given serial number found");
return false;
}
if (USBCOM422List.Count == 0)
{
_InterfaceStatus = new InterfaceStatus("No USB-COM422 device found with given serial number");
return false;
}
// Open device by serial number
ftStatus = _RS422COM.OpenBySerialNumber(USBCOM422List[0].SerialNumber);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to open USB-COM422 device", ftStatus.ToString());
return false;
}
_ID = USBCOM422List[0].SerialNumber;
// Set up device data parameters
// Set Baud rate
ftStatus = _RS422COM.SetBaudRate(_Baudrate);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to set baud rate in USB-COM422 device", ftStatus.ToString());
return false;
}
// Set data characteristics - Data bits, Stop bits, Parity
ftStatus = _RS422COM.SetDataCharacteristics(FTDI.FT_DATA_BITS.FT_BITS_8, FTDI.FT_STOP_BITS.FT_STOP_BITS_1, FTDI.FT_PARITY.FT_PARITY_NONE);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to set data characteristics in USB-COM422 device", ftStatus.ToString());
return false;
}
// Set flow control - set Xon/Xoff control OFF
ushort flowCtrl = (ushort)_FlowControl;
ftStatus = _RS422COM.SetFlowControl(flowCtrl, 0x11, 0x13);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to set flow control in USB-COM422 device", ftStatus.ToString());
return false;
}
// Set read timeout to 5 seconds, write timeout to infinite
ftStatus = _RS422COM.SetTimeouts(5000, 0);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to set timeouts in USB-COM422 device", ftStatus.ToString());
return false;
}
_Connected = true;
return true;
}
private Boolean OpenSingleConnected()
{
_InterfaceStatus = null;
UInt32 ftdiDeviceCount = 0;
FTDI.FT_STATUS ftStatus = FTDI.FT_STATUS.FT_OK;
// Determine the number of FTDI devices connected to the machine
ftStatus = _RS422COM.GetNumberOfDevices(ref ftdiDeviceCount);
// Check status
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to get number of FTDI devices",ftStatus.ToString());
return false;
}
// If no devices available, return
if (ftdiDeviceCount == 0)
{
_InterfaceStatus = new InterfaceStatus("No FTDI devices found");
return false;
}
// Allocate storage for device info list
FTDI.FT_DEVICE_INFO_NODE[] ftdiDeviceList = new FTDI.FT_DEVICE_INFO_NODE[ftdiDeviceCount];
// Populate our device list
ftStatus = _RS422COM.GetDeviceList(ftdiDeviceList);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to get FTDI devices", ftStatus.ToString());
return false;
}
// Find all USB-COM422 devices
List<FTDI.FT_DEVICE_INFO_NODE> ftdiDevices = new List<FTDI.FT_DEVICE_INFO_NODE>();
for (UInt32 i = 0; i < ftdiDeviceCount; i++)
ftdiDevices.Add(ftdiDeviceList[i]);
List<FTDI.FT_DEVICE_INFO_NODE> USBCOM422List = ftdiDevices.FindAll(delegate(FTDI.FT_DEVICE_INFO_NODE node) { return (node.Description.ToString().Contains("FTDI_USB_RS422")); });
if (USBCOM422List.Count > 1)
{
_InterfaceStatus = new InterfaceStatus("More than one USB-COM422 device found");
return false;
}
if (USBCOM422List.Count == 0 )
{
_InterfaceStatus = new InterfaceStatus("No USB-COM422 device found");
return false;
}
// Open device by serial number
ftStatus = _RS422COM.OpenBySerialNumber(USBCOM422List[0].SerialNumber);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to open USB-COM422 device", ftStatus.ToString());
return false;
}
_ID = USBCOM422List[0].SerialNumber;
// Set up device data parameters
// Set Baud rate
ftStatus = _RS422COM.SetBaudRate(_Baudrate);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to set baud rate in USB-COM422 device", ftStatus.ToString());
return false;
}
// Set data characteristics - Data bits, Stop bits, Parity
ftStatus = _RS422COM.SetDataCharacteristics(FTDI.FT_DATA_BITS.FT_BITS_8, FTDI.FT_STOP_BITS.FT_STOP_BITS_1, FTDI.FT_PARITY.FT_PARITY_NONE);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to set data characteristics in USB-COM422 device", ftStatus.ToString());
return false;
}
// Set flow control - set Xon/Xoff control OFF
ushort flowCtrl = (ushort)_FlowControl;
ftStatus = _RS422COM.SetFlowControl(flowCtrl, 0x11, 0x13);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to set flow control in USB-COM422 device", ftStatus.ToString());
return false;
}
// Set read timeout to 5 seconds, write timeout to infinite
ftStatus = _RS422COM.SetTimeouts(5000, 0);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to set timeouts in USB-COM422 device", ftStatus.ToString());
return false;
}
_Connected = true;
return true;
}
private string ReplaceDelimeters(string cmd)
{
string result = cmd;
result = result.Replace(((char)13).ToString(), "<CR>");
result = result.Replace(((char)10).ToString(), "<LF>");
return result;
}
public override DataTransferLog DataTransfer(String Command, out String _ReturnData, Int32 ReturnDataWaitms)
{
lock (lockDataTransfer) // Calling threads will wait for the current thread to finish executing the locked section.
{
DataTransferLog dataTransferLog = new DataTransferLog(ReplaceDelimeters(Command), "", this);
_ReturnData = "";
_InterfaceStatus = null;
// Construct string to send
string dataToSend = Command.Replace(" ", "");
FTDI.FT_STATUS ftStatus = FTDI.FT_STATUS.FT_OK;
UInt32 numBytesWritten = 0;
ftStatus = _RS422COM.Write(dataToSend, dataToSend.Length, ref numBytesWritten);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to write to USB-COM422 device", ftStatus.ToString());
_ReturnData = "Failed to write to USB-COM422 device | " + ftStatus.ToString();
dataTransferLog.ReturnData = _ReturnData;
return dataTransferLog;
}
// Read from devices
if (ReturnDataWaitms > 0)
{
System.Threading.Thread.Sleep(ReturnDataWaitms);
UInt32 numBytesAvailable = 0;
ftStatus = _RS422COM.GetRxBytesAvailable(ref numBytesAvailable);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to get number of bytes available to read from USB-COM422 device", ftStatus.ToString());
_ReturnData = "Failed to get number of bytes available to read from USB-COM422 device | " + ftStatus.ToString();
dataTransferLog.ReturnData = _ReturnData;
return dataTransferLog;
}
// Now that we have the amount of data we want available, read it
string readData;
UInt32 numBytesRead = 0;
// Note that the Read method is overloaded, so can read string or byte array data
ftStatus = _RS422COM.Read(out readData, numBytesAvailable, ref numBytesRead);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to read data from USB-COM422 device", ftStatus.ToString());
_ReturnData = "Failed to read data from USB-COM422 device | " + ftStatus.ToString();
dataTransferLog.ReturnData = _ReturnData;
return dataTransferLog;
}
_ReturnData = readData.Trim();
dataTransferLog.ReturnData = _ReturnData;
}
else
{
_ReturnData = "not requested";
dataTransferLog.ReturnData = _ReturnData;
}
return dataTransferLog;
} // End lock
}
public override string ToString()
{
return string.Format("{0}.{1}: Baud {2:0}, Flowcontrol {3}", _Type, _ID, _Baudrate, _FlowControl.ToString());
}
}
}

View File

@@ -0,0 +1,407 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FTD2XX_NET;
using ChamChat.Models;
namespace ChamChat
{
// Communication with FDTI USB-COM485-Plus1
public class FDTI_USB_COM485 : Interface
{
public FDTI_USB_COM485(String ID)
: base(ID)
{
_Type = InterfaceType.FDTI_USB_COM485;
}
public FDTI_USB_COM485()
: base()
{
_Type = InterfaceType.FDTI_USB_COM485;
}
// Properties and fields
private static FTDI _RS485COM = new FTDI();
private static uint _Baudrate = 9600;
private static FlowControl _FlowControl = FlowControl.FT_FLOW_NONE;
private System.Object lockDataTransfer = new System.Object();
private bool _Connected = false; public Boolean Connected { get { return _Connected; } }
public override Boolean Open()
{
bool result;
if (_ID != null)
result = OpenByID();
else
result = OpenSingleConnected();
return result;
}
public override Boolean Close()
{
_RS485COM.Close();
_Connected = false;
_RS485COM = null;
return true;
}
private Boolean OpenByID()
{
_InterfaceStatus = null;
UInt32 ftdiDeviceCount = 0;
FTDI.FT_STATUS ftStatus = FTDI.FT_STATUS.FT_OK;
// Determine the number of FTDI devices connected to the machine
ftStatus = _RS485COM.GetNumberOfDevices(ref ftdiDeviceCount);
// Check status
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to get number of FTDI devices", ftStatus.ToString());
return false;
}
// If no devices available, return
if (ftdiDeviceCount == 0)
{
_InterfaceStatus = new InterfaceStatus("No FTDI devices found");
return false;
}
// Allocate storage for device info list
FTDI.FT_DEVICE_INFO_NODE[] ftdiDeviceList = new FTDI.FT_DEVICE_INFO_NODE[ftdiDeviceCount];
// Populate our device list
ftStatus = _RS485COM.GetDeviceList(ftdiDeviceList);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to get FTDI devices", ftStatus.ToString());
return false;
}
// Find all USB-COM485 devices
List<FTDI.FT_DEVICE_INFO_NODE> ftdiDevices = new List<FTDI.FT_DEVICE_INFO_NODE>();
for (UInt32 i = 0; i < ftdiDeviceCount; i++)
ftdiDevices.Add(ftdiDeviceList[i]);
List<FTDI.FT_DEVICE_INFO_NODE> USBCOM485List = ftdiDevices.FindAll(delegate(FTDI.FT_DEVICE_INFO_NODE node) { return node.SerialNumber == _ID; });
if (USBCOM485List.Count > 1)
{
_InterfaceStatus = new InterfaceStatus("More than one USB-COM485 devices with given serial number found");
return false;
}
if (USBCOM485List.Count == 0)
{
_InterfaceStatus = new InterfaceStatus("No USB-COM485 device found with given serial number");
return false;
}
// Open device by serial number
ftStatus = _RS485COM.OpenBySerialNumber(USBCOM485List[0].SerialNumber);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to open USB-COM485 device", ftStatus.ToString());
return false;
}
_ID = USBCOM485List[0].SerialNumber;
// Set up device data parameters
// Set Baud rate
ftStatus = _RS485COM.SetBaudRate(_Baudrate);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to set baud rate in USB-COM485 device", ftStatus.ToString());
return false;
}
// Set data characteristics - Data bits, Stop bits, Parity
ftStatus = _RS485COM.SetDataCharacteristics(FTDI.FT_DATA_BITS.FT_BITS_8, FTDI.FT_STOP_BITS.FT_STOP_BITS_1, FTDI.FT_PARITY.FT_PARITY_NONE);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to set data characteristics in USB-COM485 device", ftStatus.ToString());
return false;
}
// Set flow control - set Xon/Xoff control OFF
ushort flowCtrl = (ushort)_FlowControl;
ftStatus = _RS485COM.SetFlowControl(flowCtrl, 0x11, 0x13);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to set flow control in USB-COM485 device", ftStatus.ToString());
return false;
}
// Set read timeout to 5 seconds, write timeout to infinite
ftStatus = _RS485COM.SetTimeouts(5000, 0);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to set timeouts in USB-COM485 device", ftStatus.ToString());
return false;
}
_Connected = true;
return true;
}
private Boolean OpenSingleConnected()
{
_InterfaceStatus = null;
UInt32 ftdiDeviceCount = 0;
FTDI.FT_STATUS ftStatus = FTDI.FT_STATUS.FT_OK;
// Determine the number of FTDI devices connected to the machine
ftStatus = _RS485COM.GetNumberOfDevices(ref ftdiDeviceCount);
// Check status
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to get number of FTDI devices",ftStatus.ToString());
return false;
}
// If no devices available, return
if (ftdiDeviceCount == 0)
{
_InterfaceStatus = new InterfaceStatus("No FTDI devices found");
return false;
}
// Allocate storage for device info list
FTDI.FT_DEVICE_INFO_NODE[] ftdiDeviceList = new FTDI.FT_DEVICE_INFO_NODE[ftdiDeviceCount];
// Populate our device list
ftStatus = _RS485COM.GetDeviceList(ftdiDeviceList);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to get FTDI devices", ftStatus.ToString());
return false;
}
// Find all USB-COM485 devices
List<FTDI.FT_DEVICE_INFO_NODE> ftdiDevices = new List<FTDI.FT_DEVICE_INFO_NODE>();
for (UInt32 i = 0; i < ftdiDeviceCount; i++)
ftdiDevices.Add(ftdiDeviceList[i]);
List<FTDI.FT_DEVICE_INFO_NODE> USBCOM485List = ftdiDevices.FindAll(delegate(FTDI.FT_DEVICE_INFO_NODE node) { return (node.Description.ToString().Contains("FTDI_USB_RS485")); });
if (USBCOM485List.Count > 1)
{
_InterfaceStatus = new InterfaceStatus("More than one USB-COM485 device found");
return false;
}
if (USBCOM485List.Count == 0 )
{
_InterfaceStatus = new InterfaceStatus("No USB-COM485 device found");
return false;
}
// Open device by serial number
ftStatus = _RS485COM.OpenBySerialNumber(USBCOM485List[0].SerialNumber);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to open USB-COM485 device", ftStatus.ToString());
return false;
}
_ID = USBCOM485List[0].SerialNumber;
// Set up device data parameters
// Set Baud rate
ftStatus = _RS485COM.SetBaudRate(_Baudrate);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to set baud rate in USB-COM485 device", ftStatus.ToString());
return false;
}
// Set data characteristics - Data bits, Stop bits, Parity
ftStatus = _RS485COM.SetDataCharacteristics(FTDI.FT_DATA_BITS.FT_BITS_8, FTDI.FT_STOP_BITS.FT_STOP_BITS_1, FTDI.FT_PARITY.FT_PARITY_NONE);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to set data characteristics in USB-COM485 device", ftStatus.ToString());
return false;
}
// Set flow control - set Xon/Xoff control OFF
ushort flowCtrl = (ushort)_FlowControl;
ftStatus = _RS485COM.SetFlowControl(flowCtrl, 0x11, 0x13);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to set flow control in USB-COM485 device", ftStatus.ToString());
return false;
}
// Set read timeout to 5 seconds, write timeout to infinite
ftStatus = _RS485COM.SetTimeouts(5000, 0);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to set timeouts in USB-COM485 device", ftStatus.ToString());
return false;
}
_Connected = true;
return true;
}
private string NOTINUSE_ReplaceDelimeters(string cmd)
{
string result = cmd;
result = result.Replace(((char)13).ToString(), "<CR>");
result = result.Replace(((char)10).ToString(), "<LF>");
return result;
}
public override DataTransferLog DataTransfer(String Command, out String _ReturnData, Int32 ReturnDataWaitms)
{
lock (lockDataTransfer) // Calling threads will wait for the current thread to finish executing the locked section.
{
DataTransferLog dataTransferLog = new DataTransferLog(ANSI_X328.ToANSI(Command), "", this);
_ReturnData = "";
_InterfaceStatus = null;
// Construct string to send
string dataToSend = Command.Replace(" ", "");
FTDI.FT_STATUS ftStatus = FTDI.FT_STATUS.FT_OK;
UInt32 numBytesWritten = 0;
ftStatus = _RS485COM.Write(dataToSend, dataToSend.Length, ref numBytesWritten);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to write to USB-COM485 device", ftStatus.ToString());
_ReturnData = "Failed to write to USB-COM485 device | " + ftStatus.ToString();
dataTransferLog.ReturnData = _ReturnData;
return dataTransferLog;
}
// Read from devices
if (ReturnDataWaitms > 0)
{
System.Threading.Thread.Sleep(ReturnDataWaitms);
UInt32 numBytesAvailable = 0;
ftStatus = _RS485COM.GetRxBytesAvailable(ref numBytesAvailable);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to get number of bytes available to read from USB-COM485 device", ftStatus.ToString());
_ReturnData = "Failed to get number of bytes available to read from USB-COM485 device | " + ftStatus.ToString();
dataTransferLog.ReturnData = _ReturnData;
return dataTransferLog;
}
// Now that we have the amount of data we want available, read it
string readData;
UInt32 numBytesRead = 0;
// Note that the Read method is overloaded, so can read string or byte array data
ftStatus = _RS485COM.Read(out readData, numBytesAvailable, ref numBytesRead);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
_InterfaceStatus = new InterfaceStatus("Failed to read data from USB-COM485 device", ftStatus.ToString());
_ReturnData = "Failed to read data from USB-COM485 device | " + ftStatus.ToString();
dataTransferLog.ReturnData = _ReturnData;
return dataTransferLog;
}
_ReturnData = readData.Trim();
dataTransferLog.ReturnData = _ReturnData;
}
else
{
_ReturnData = "not requested";
dataTransferLog.ReturnData = _ReturnData;
}
return dataTransferLog;
} // End lock
}
public override string ToString()
{
string comPortName = "COM N/A";
try
{
_RS485COM.GetCOMPort(out comPortName);
}
catch { }
byte latency = 0;
try
{
_RS485COM.GetLatency(ref latency);
}
catch { }
return string.Format("{0}.{1} on {2}: Baud {3:0}, Flowcontrol {4}, Latency {5}", _Type, _ID,comPortName, _Baudrate, _FlowControl.ToString(), latency.ToString());
}
}
}

View File

@@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ChamChat
{
// Hard coded system properties.
public static class Interfaces
{
public static List<Interface> GetAll()
{
List<Interface> result = new List<Interface>();
Interface intFace;
// Add known device
intFace = new FDTI_USB_COM422("USB_RS422_MOD_1");
if (intFace.Open())
result.Add(intFace);
// Add known device
intFace = new FDTI_USB_COM422("USB_RS422_MOD_2");
if (intFace.Open())
result.Add(intFace);
// Add known device
intFace = new FDTI_USB_COM422("USB_RS422_WE_1");
if (intFace.Open())
result.Add(intFace);
// Add known device
intFace = new FDTI_USB_COM485("USB_RS485_MOD_1");
if (intFace.Open())
result.Add(intFace);
// Add known device
intFace = new FDTI_USB_RS232("USB_RS232_WE_1");
if (intFace.Open())
result.Add(intFace);
return result;
}
}
}

View File

@@ -0,0 +1,44 @@

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace ChamChat
{
public static class Layouts
{
public static void Buttons(Control control)
{
FlatStyle flatStyle = FlatStyle.Flat;
if (control.GetType() == typeof(Button))
{
Button b = (Button)control;
b.FlatStyle = flatStyle;
}
foreach (Control child in control.Controls)
{
Buttons(child);
}
}
public static void DataGridViewNotSortable(DataGridView dgv)
{
foreach (DataGridViewColumn column in dgv.Columns)
column.SortMode = DataGridViewColumnSortMode.NotSortable;
}
}
}

View File

@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
namespace ChamChat
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new ChamChat());
}
}
}

View File

@@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace ChamChat
{
public static class PromptProgramNo
{
public static int Value = 0;
private static bool valueSet;
public static bool ShowDialog(int Minimum, int Maximum)
{
Form prompt = new Form();
prompt.Width = 235;
prompt.Height = 130;
prompt.Text = "Import program form client";
//prompt.TopMost = true;
prompt.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
prompt.ControlBox = false;
prompt.StartPosition = FormStartPosition.CenterParent;
Label textLabel = new Label() { Left = 16, Top = 16, Text = "Select the program to import!" };
textLabel.AutoSize = true;
NumericUpDown inputBox = new NumericUpDown() { Left = 163, Top = 14, Width = 43, Height = 20 };
inputBox.Minimum = Minimum;
inputBox.Maximum = Maximum;
inputBox.Value = Minimum;
Value = Minimum;
inputBox.ValueChanged += (sender, e) => { Value = (int)inputBox.Value; };
Button confirmation = new Button() { Text = "OK", Left = 131, Top = 54, Width = 75, Height = 23 };
confirmation.Click += (sender, e) => { valueSet = true; prompt.Close(); };
Button cancel = new Button() { Text = "Cancel", Left = 19, Top = 54, Width = 75, Height = 23 };
cancel.Click += (sender, e) => { valueSet= false; prompt.Close(); };
prompt.Controls.Add(confirmation);
prompt.Controls.Add(cancel);
prompt.Controls.Add(textLabel);
prompt.Controls.Add(inputBox);
prompt.ShowDialog();
return valueSet;
}
}
}

View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("SPeak")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Microsoft")]
[assembly: AssemblyProduct("SPeak")]
[assembly: AssemblyCopyright("Copyright © Microsoft 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("a0d149fe-a1b8-4ffd-8901-5459f33b770a")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -0,0 +1,63 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace ChamChat.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ChamChat.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}

View File

@@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -0,0 +1,50 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace ChamChat.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("0")]
public int Client {
get {
return ((int)(this["Client"]));
}
set {
this["Client"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string ProfileFilename {
get {
return ((string)(this["ProfileFilename"]));
}
set {
this["ProfileFilename"] = value;
}
}
}
}

View File

@@ -0,0 +1,12 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="SPeak.Properties" GeneratedClassName="Settings">
<Profiles />
<Settings>
<Setting Name="Client" Type="System.Int32" Scope="User">
<Value Profile="(Default)">0</Value>
</Setting>
<Setting Name="ProfileFilename" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
</Settings>
</SettingsFile>

View File

@@ -0,0 +1,18 @@
<?xml version="1.0"?>
<configuration>
<configSections>
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="SPeak.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
</sectionGroup>
</configSections>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup><userSettings>
<SPeak.Properties.Settings>
<setting name="Client" serializeAs="String">
<value>0</value>
</setting>
<setting name="ProfileFilename" serializeAs="String">
<value />
</setting>
</SPeak.Properties.Settings>
</userSettings>
</configuration>

BIN
ChamChat/ChamChat/icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@@ -0,0 +1,4 @@
// <autogenerated />
using System;
using System.Reflection;
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.0", FrameworkDisplayName = ".NET Framework 4")]

View File

@@ -0,0 +1 @@
48272d1c474abd70b671bd09b41ba43c29c5bc67

View File

@@ -0,0 +1,5 @@
\\silicium\software\MASER software\Source\ChamChat\ChamChat\obj\x86\Release\ChamChat.csproj.AssemblyReference.cache
\\silicium\software\MASER software\Source\ChamChat\ChamChat\obj\x86\Release\ChamChat.ChamChat.resources
\\silicium\software\MASER software\Source\ChamChat\ChamChat\obj\x86\Release\ChamChat.Properties.Resources.resources
\\silicium\software\MASER software\Source\ChamChat\ChamChat\obj\x86\Release\ChamChat.csproj.GenerateResource.cache
\\silicium\software\MASER software\Source\ChamChat\ChamChat\obj\x86\Release\ChamChat.csproj.CoreCompileInputs.cache

View File

@@ -0,0 +1,308 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ChamChat.Models;
namespace ChamChat
{
public partial class HTS7057_Client : Client
{
private const Int32 _OptionRange = 4000;
private const Int32 _DataTransferTimeOut = 1000;
private DateTime _ReadyToSend = DateTime.Now; // Timestamp when client is ready to communicate
private DateTime _dtTestStart = DateTime.Now;
public HTS7057_Client(Int32 MIDS, ClientType Type)
: base(MIDS, Type)
{
// Set options available in client
_Parameters = new List<Parameter>();
_Parameters.Add(Parameter.T);
//_Parameters.Add(Parameter.RampT);
// Add option range
_ClientOptions = new List<ProfileOption>();
foreach (ProfileOption o in Enum.GetValues(typeof(ProfileOption)))
if ((int)o >= _OptionRange && (int)o < _OptionRange+999)
_ClientOptions.Add(o);
_InterfaceType = InterfaceType.FDTI_USB_COM422;
}
public override Profile ReadProfile(int RAM, ref System.ComponentModel.BackgroundWorker bgw)
{
String title = string.Format("{0:00000} {1}", _MIDS, _Type.ToStr());
List<Step> steps = new List<Step>();
Step step = new Step(365 * 24 * 60);
string cmd;
string read;
cmd = string.Format("${0:00}I", _Address);
DataTransfer(cmd, out read, _DataTransferTimeOut);
if (read.Length >= 6)
{
double sw = 0;
if (double.TryParse(read.Substring(0, 6), out sw))
{
step.T = sw;
}
}
steps.Add(step);
return new Profile(title, steps, new List<Loop>(), new List<ProfileOption>());
}
public override Boolean WriteProfile(Profile profile)
{
return WriteProfile(profile, -1);
}
public override Boolean WriteProfile(Profile profile, int RAM)
{
// Only stand alone profiles allowed!
if (!IsProgrammable(profile))
return false;
_Profile = profile;
return true;
}
public override Boolean IsProgrammable(Profile profile)
{
// Profile is programmable if all below applies
// Profile contains just 1 step
if (profile.SerializedStepList.Count != 1)
{
_ClientMessages.Add(new ClientMessage("Temperature range is -70 to 200 °C"));
return false;
}
Step step = profile.SerializedStepList[0];
// Temperature is limited between -70 & 200 °C
if (step.T < -70 || step.T > 200)
{
_ClientMessages.Add(new ClientMessage("Temperature range is -70 to 200 °C"));
return false;
}
return true;
}
// To do
public override Boolean HasAlarm(out List<Alarm> alarms)
{
alarms = new List<Alarm>();
return true;
}
public override Boolean IsIdle()
{
// Chamber is idle if return value's last 16 chars are 0
string cmd;
string read;
cmd = string.Format("${0:00}I", _Address);
DataTransfer(cmd, out read, _DataTransferTimeOut);
try
{
if (read.Substring(15,1) == "0")
return true;
}
catch { }
return false;
}
public override Boolean Start()
{
// Command consists of $01E xXxx.x bbbbbbbb
// The minus sign for temperature must be on location of X
// Bit 3 is on/off bit of chamber (return as bit 1 in 16-bit output)
// Bit 5 is on/off bit of heater/cooler (return as bit 3 in 16-bit output)
if (_Profile == null)
return false;
string cmd;
string read;
double t = _Profile.Steps[0].T;
if( t< 0)
cmd = string.Format("${0:00}E 0-{1:00.0} 00010100", _Address, Math.Abs(t));
else
cmd = string.Format("${0:00}E {1:0000.0} 00010100", _Address, t);
DataTransfer(cmd, out read, _DataTransferTimeOut);
_dtTestStart = DateTime.Now;
return TxRxSucces(cmd, read);
}
public override Boolean IsFinished()
{
// Chambers does not finish on its own
return IsIdle();
}
public override Boolean Stop()
{
string cmd;
string read;
cmd = string.Format("${0:00}E 0023.0 00000000", _Address);
DataTransfer(cmd, out read, _DataTransferTimeOut);
return TxRxSucces(cmd, read);
}
public override Boolean IsOnline()
{
// Chamber is online if Sollwert in °C is returned
string cmd;
string read;
cmd = string.Format("${0:00}I", _Address);
DataTransfer(cmd, out read, _DataTransferTimeOut);
if (read.Length < 6)
return false;
double sw = 0;
if (double.TryParse(read.Substring(0, 6), out sw))
return true;
return false;
}
public override String Progress()
{
string cmd;
string read;
cmd = string.Format("${0:00}I", _Address);
DataTransfer(cmd, out read, _DataTransferTimeOut);
if (read.Length < 13)
return "n/a";
string progress = "";
double sw = 0;
if (double.TryParse(read.Substring(0, 6), out sw))
progress += string.Format("Setting is {0:0.0} °C", sw);
double iw = 0;
if (double.TryParse(read.Substring(7, 6), out iw))
progress += string.Format(", current temperature is {0:0.0} °C",iw);
if (progress.Length == 0)
progress += "n/a";
return progress;
}
private bool TxRxSucces(string cmd, string read)
{
if (cmd.Contains("I"))
if (read.Length == 30)
if (read.Substring(4, 1) == "." && read.Substring(11, 1) == ".")
return true;
if (cmd.Contains("E"))
return read == "0";
return false;
}
// Performs transfer and adds interface logs to list in Client parent class
private Boolean DataTransfer(string cmd, out string read, int ReturnDataWaitms)
{
// If no maximum number of attempts is given, it defaults to 3.
return DataTransfer(cmd, out read, ReturnDataWaitms, 3);
}
// Performs transfer and adds interface logs to list in Client parent class
private Boolean DataTransfer(string cmd, out string read, int ReturnDataWaitms, int MaxNumOfAttempts)
{
// Construct command to send
cmd += (char)13; // CR
cmd = cmd.Replace(" ", "");
// Wait for _ReadyToSend or max 1 seconds
DateTime go = DateTime.Now.AddSeconds(1);
while (DateTime.Now < _ReadyToSend && DateTime.Now < go)
System.Threading.Thread.Sleep(50);
read = "";
bool success = false;
int attempts = 0;
while (!success && attempts <= MaxNumOfAttempts)
{
DataTransferLog log = _Interface.DataTransfer(cmd, out read, ReturnDataWaitms);
success = TxRxSucces(cmd, read);
attempts++;
// Mask for showing in GUI
if (cmd.Contains("I"))
log.ShowInGUI = false;
// Notify user via GUI of failed attempts
if (attempts > 1)
log.Command += string.Format(" [Attempt {0:0}]", attempts);
// Add to logs
AppendDataTransferLog(log);
// Set _ReadyToSend acc. manual specs
_ReadyToSend = DateTime.Now.AddMilliseconds(2000);
// Sleeps
if (!success)
System.Threading.Thread.Sleep(3000); // Sleep 3 seconds before resending if failed
}
return success;
}
}
}

View File

@@ -0,0 +1,61 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{B03537FE-EF64-42E3-A8C0-25C79BB818A7}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Speak</RootNamespace>
<AssemblyName>HTS7057</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Client.HTS7057.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Task.HTS7057.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Models\Models.csproj">
<Project>{09375A4A-28B8-427B-853D-75C03A070728}</Project>
<Name>Models</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Client_HTS7057")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Microsoft")]
[assembly: AssemblyProduct("Client_HTS7057")]
[assembly: AssemblyCopyright("Copyright © Microsoft 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("3e41095f-2a04-41f7-989a-d2705d89e835")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -0,0 +1,226 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ChamChat.Models;
namespace ChamChat
{
public class HTS7057_Task : Task
{
// Each step is separately programmed to the TSE11.
// Steps are programmed at 110% of required step duration.
// End of program is always of shutdown type to avoid stressing to much. (Excluding last step)
// If next step is of different type (tA or tB), then the next temperature is prepared in other chamber.
// Default temperatures are 0 °C for tA and 85 °C for tB.
public HTS7057_Task(Client Client, Profile Profile)
: base(Client, Profile)
{
_Profile = Profile;
_Client = Client;
_SerSteps = _Profile.SerializedStepList;
}
// Needs to be overriden, because chamber is never stand alone programmable
public override Boolean IsStandAloneProgrammable(Profile profile)
{
return false;
}
private const Int32 PollingIntervalSeconds = 10;
private List<Step> _SerSteps;
public override Boolean IsControlledProgrammable(Profile profile)
{
foreach (Step step in profile.SerializedStepList)
{
List<Step> steps = new List<Step>();
steps.Add(step);
Profile p = new Profile(_Client.Type.ToStr(), steps, new List<Loop>(), profile.Options);
if (!_Client.IsProgrammable(p))
return false;
}
return true;
}
protected override void ThreadStandAlone()
{
_Status = TaskStatus.Aborted;
_TaskProgress = "Client cannot operate in standaline mode";
_isKicking = false;
}
protected override void ThreadControlled()
{
Int32 iCurrentSerialStep = -1;
DateTime startOfCurrentProgram = new DateTime(1900, 1, 1);
DateTime endOfCurrentProgram = new DateTime(1900, 1, 1);
Step currentStep = _SerSteps[0];
DateTime lastPolled = DateTime.Now;
while (_Status == TaskStatus.IsRunning)
{
if (DateTime.Now > endOfCurrentProgram)
{
iCurrentSerialStep += 1;
// Last step has been performed?
if (iCurrentSerialStep > _SerSteps.Count - 1)
{
// Do not stop client, but leave running if option given
if (_Profile.Options.Contains(ProfileOption.HTS7057_EndModeHold))
{
_Status = TaskStatus.Finished;
AddEventLog(ProfileOption.HTS7057_EndModeHold.ToStr());
_TaskProgress = ProfileOption.HTS7057_EndModeOff.ToStr();
_TaskProgress += string.Format(" (setting is {0:0.0} °C)", _SerSteps[_SerSteps.Count - 1].T);
continue;
}
else
{
_Client.Stop();
_Status = TaskStatus.Finished;
AddEventLog(ProfileOption.HTS7057_EndModeOff.ToStr());
_TaskProgress = ProfileOption.HTS7057_EndModeOff.ToStr();
continue;
}
}
Profile newProfile = GetProfile(iCurrentSerialStep);
currentStep = _SerSteps[iCurrentSerialStep];
AddEventLog(string.Format("{0} minutes @ {1:0.0} °C", _SerSteps[iCurrentSerialStep].DurationMin, _SerSteps[iCurrentSerialStep].T));
RestartClient(newProfile);
if (_Status != TaskStatus.IsRunning) // Might be altered in RestartClient()
continue;
// Update variables
startOfCurrentProgram = DateTime.Now;
endOfCurrentProgram = startOfCurrentProgram.AddMinutes(newProfile.DurationMin);
lastPolled = DateTime.Now;
}
// Poll only every 'PollingIntervalSeconds' seconds
if (DateTime.Now > lastPolled.AddSeconds(PollingIntervalSeconds))
{
// Is finished?
try
{
if (_Client.IsFinished())
{
_Status = TaskStatus.Interrupted; // Profile did not finish, client did
continue;
}
}
catch { }
try
{
double taskRunTimeMin = (DateTime.Now - _startThread).TotalMinutes;
double pTest = Math.Max(0,Math.Min(100, Math.Floor(taskRunTimeMin / _Profile.DurationMin * 100)));
double stepRuntime = (DateTime.Now - startOfCurrentProgram).TotalMinutes;
double pStep = Math.Max(0,Math.Min(100, Math.Floor(stepRuntime / _SerSteps[iCurrentSerialStep].DurationMin * 100)));
double taskTimeRemain = Math.Max(0, _Profile.DurationMin - taskRunTimeMin);
double taskTimeRemainHrs = Math.Floor(taskTimeRemain / 60);
double taskTimeRemainMin = Math.Floor(taskTimeRemain - 60 * taskTimeRemainHrs);
_TaskProgress = String.Format("Step #{0:00}/{1:00} progress {2:0}%, test progress {3:0}%, remaining test time {4:0}h{5:00}m", iCurrentSerialStep + 1, _Profile.SerializedStepList.Count, pStep, pTest, taskTimeRemainHrs, taskTimeRemainMin);
}
catch
{
_TaskProgress = "Progress could not be calculated.";
}
lastPolled = DateTime.Now;
}
System.Threading.Thread.Sleep(200);
if (_Status == TaskStatus.AbortRequested)
{
try
{
if (_Client.Stop())
_Status = TaskStatus.Aborted;
}
catch { }
}
_isKicking = true;
}
_isKicking = false;
}
private void RestartClient(Profile newProfile)
{
// Write profile
try
{
if (!_Client.WriteProfile(newProfile))
{
_Status = TaskStatus.Interrupted;
return;
}
}
catch (Exception ex)
{
_Status = TaskStatus.ExceptionOccured;
_TaskProgress = string.Format("Client WriteProfile() exception: {0}", ex.Message);
AddEventLog(_TaskProgress);
return;
}
// Start client
try
{
//AddEventLog("RestartClient.Start");
if (!_Client.Start())
{
_Status = TaskStatus.Interrupted;
return;
}
}
catch (Exception ex)
{
_Status = TaskStatus.ExceptionOccured;
_TaskProgress = string.Format("Client Start() exception: {0}", ex.Message);
AddEventLog(_TaskProgress);
return;
}
}
private Profile GetProfile(int iStep)
{
// Stepslist
List<Step> steps = new List<Step>();
steps.Add(_SerSteps[iStep].DeepClone());
// Loops
List<Loop> loops = new List<Loop>();
// Options
List<ProfileOption> options = new List<ProfileOption>();
// Create profile
return new Profile(_Profile.Title, steps, loops, options);
}
}
}

View File

@@ -0,0 +1,4 @@
// <autogenerated />
using System;
using System.Reflection;
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.0", FrameworkDisplayName = ".NET Framework 4")]

View File

@@ -0,0 +1 @@
78ce0a1107047916b3702a482dea8e66722a26e2

View File

@@ -0,0 +1,2 @@
\\silicium\software\MASER software\Source\ChamChat\Client_HTS7057\obj\Release\Client_HTS7057.csproj.AssemblyReference.cache
\\silicium\software\MASER software\Source\ChamChat\Client_HTS7057\obj\Release\Client_HTS7057.csproj.CoreCompileInputs.cache

View File

@@ -0,0 +1,428 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ChamChat.Models;
namespace ChamChat
{
public partial class LHL113_Client : Client
{
private const Int32 _OptionRange = 3000;
private const Int32 _DataTransferTimeOut = 1000;
private DateTime _ReadyToSend = DateTime.Now; // Timestamp when client is ready to communicate
private const int _RAM = 1;
private DateTime _dtTestStart = DateTime.Now;
// To do
public LHL113_Client(Int32 MIDS, ClientType Type)
: base(MIDS, Type)
{
// Set options available in client
_Parameters = new List<Parameter>();
_Parameters.Add(Parameter.T);
_Parameters.Add(Parameter.RH);
_Parameters.Add(Parameter.RampT);
_Parameters.Add(Parameter.RampRH);
// Add option range
_ClientOptions = new List<ProfileOption>();
foreach (ProfileOption o in Enum.GetValues(typeof(ProfileOption)))
if ((int)o >= _OptionRange && (int)o < _OptionRange+999)
_ClientOptions.Add(o);
// Set availabel addresses for programming
_AvailableRAMs = new List<int>();
for (int i = 1; i < 31; i++)
_AvailableRAMs.Add(i);
_InterfaceType = InterfaceType.FDTI_USB_COM422;
}
// To do
public override Profile ReadProfile(int RAM, ref System.ComponentModel.BackgroundWorker bgw)
{
string sAddr = _Address.ToString();
string cmd;
string read;
Profile profile = new Profile();
try
{
// Communicate with client
cmd = sAddr + ",PRGMREAD,";
DataTransfer(cmd, out read, _DataTransferTimeOut);
List<Step> steps = new List<Step>();
List<Loop> loops = new List<Loop>();
List<ProfileOption> options = new List<ProfileOption>();
String name = "LHL113_Client";
// Create profile
profile = new Profile(name, steps, loops, options);
}
catch
{
}
return profile;
}
public override Boolean WriteProfile(Profile profile)
{
return WriteProfile(profile, _RAM);
}
public override Boolean WriteProfile(Profile profile, int RAM)
{
// Only stand alone profiles allowed!
if (!IsProgrammable(profile))
return false;
string sRAM = String.Format("{0:0}", RAM);
string sCmdStart = _Address.ToString() + ", PRGM DATA WRITE, PGM:" + sRAM + ", ";
string cmd;
string read;
// Set to STANDBY if OFF
cmd = _Address.ToString() + ", MODE?";
DataTransfer(cmd, out read, _DataTransferTimeOut);
if (read.Contains("OFF"))
{
cmd = _Address.ToString() + ", MODE, STANDBY";
DataTransfer(cmd, out read, _DataTransferTimeOut);
}
// Communicate with client (page 49)
cmd = sCmdStart + "EDIT START";
DataTransfer(cmd, out read, _DataTransferTimeOut);
for (int i = 0; i < profile.SerializedStepList.Count; i++)
{
Step step = profile.SerializedStepList[i];
cmd = sCmdStart;
cmd += string.Format("STEP{0:0}, ", i + 1);
cmd += string.Format("TEMP{0:00.0}, ", step.T);
if (step.RampCtrlT) cmd += "TRAMPON,"; else cmd += "TRAMPOFF,";
cmd += string.Format("HUMI{0:00}, ", step.RH);
if (step.RampCtrlRH) cmd += "HRAMPON,"; else cmd += "HRAMPOFF,";
if (step.Hours < 100)
cmd += string.Format("TIME{0:00}:{1:00}, ", step.Hours, step.Minutes);
else
cmd += string.Format("TIME{0:00}:00, ", step.Hours);
cmd += "GRANTY OFF, ";
DataTransfer(cmd, out read, _DataTransferTimeOut);
System.Threading.Thread.Sleep(500);
}
// End options (off is default)
if (profile.Options.Contains(ProfileOption.LHL113_EndModeHold))
cmd = sCmdStart + "END, HOLD";
else
cmd = sCmdStart + "END, OFF";
DataTransfer(cmd, out read, _DataTransferTimeOut);
// Loop (see page 50)
if (profile.Loops.Count == 1)
{
Loop l = profile.Loops[0];
cmd = sCmdStart + String.Format("COUNT, ({0:0}. {1:0}. {2:0})", l.First, l.Last, l.N);
DataTransfer(cmd, out read, _DataTransferTimeOut);
}
cmd = sCmdStart + "EDIT END";
DataTransfer(cmd, out read, _DataTransferTimeOut);
Boolean result = false;
if (_Interface.InterfaceStatus == null)
result = true;
_Profile = profile;
return result;
}
public override Boolean IsProgrammable(Profile profile)
{
// Profile is programmable if all below applies
// Step is at least 3 minutes
foreach (Step step in profile.Steps)
if (step.DurationMin < 3)
return false;
// Temperature is limited between 30 & 90 °C
foreach (Step step in profile.Steps)
if (step.T < 30 || step.T > 90)
return false;
// RH is limited between 60 & 95 °C
foreach (Step step in profile.Steps)
if (step.RH < 60 || step.RH > 95)
return false;
// Only one program of a max of 9 steps and a maximum of 99 repeated steps can be stored at a time (page 44 of user's manual).
if (profile.Steps.Count > 9)
return false;
if (profile.Loops.Count == 1)
{
if (profile.Loops[0].N > 99)
return false;
}
else
{
if (profile.SerializedStepList.Count > 9)
return false;
}
return true;
}
// To do
public override Boolean HasAlarm(out List<Alarm> alarms)
{
alarms = new List<Alarm>();
return true;
}
public override Boolean IsIdle()
{
// IsIdle() returns true if status of chamber is 'Standby'. See page 31 MODE?.
string sAddr = _Address.ToString();
string cmd;
string read;
cmd = sAddr + ", MODE?";
DataTransfer(cmd, out read, _DataTransferTimeOut);
if (read.Contains("STANDBY") || read.Contains("OFF"))
return true;
return false;
}
public override Boolean Start()
{
if (_Profile == null)
return false;
string sAddr = _Address.ToString();
string cmd;
string read;
cmd = sAddr + ", MODE, RUN "+_RAM; // See page 47.
DataTransfer(cmd, out read, _DataTransferTimeOut);
_dtTestStart = DateTime.Now;
return TxRxSucces(cmd, read);
}
public override Boolean IsFinished()
{
// Finished() returns true if chamber is not running. See page 34 MODE?.
string sAddr = _Address.ToString();
string cmd;
string read;
cmd = sAddr + ", MODE?";
DataTransfer(cmd, out read, _DataTransferTimeOut);
if (read.Contains("OFF") || read.Contains("STANDBY"))
return true;
return false;
}
public override Boolean Stop()
{
string sAddr = _Address.ToString();
string cmd;
string read;
cmd = sAddr + ", MODE, STANDBY"; // Pg. 47
DataTransfer(cmd, out read, _DataTransferTimeOut);
return TxRxSucces(cmd, read);
}
public override Boolean IsOnline()
{
try
{
string sAddr = _Address.ToString();
string cmd;
string read;
cmd = sAddr + ", ROM?"; // Pg. 27
DataTransfer(cmd, out read, _DataTransferTimeOut);
return read.ToLower().Contains("jlc");
}
catch
{
return false;
}
}
public override String Progress()
{
string sAddr = _Address.ToString();
string cmd;
string read;
//cmd = sAddr + ", MON?"; // See page 31
//DataTransfer(cmd, out read, _DataTransferTimeOut);
//Double T = Double.Parse(read.Split(',')[0]);
//Double RH = Double.Parse(read.Split(',')[1]);
cmd = sAddr + ", PRGM MON?"; // See page 35
DataTransfer(cmd, out read, _DataTransferTimeOut);
int step = Int32.Parse(read.Split(',')[1]) - 1;
Double Tset = Double.Parse(read.Split(',')[2]);
Double RHset = Double.Parse(read.Split(',')[3]);
string time = read.Split(',')[4];
int hrs = Int32.Parse(time.Split(':')[0]);
int min = Int32.Parse(time.Split(':')[1]);
int cyclesLeft = Int32.Parse(read.Split(',')[5]);
double stepTimeLeft = hrs * 60 + min;
double stepDuration = _Profile.SerializedStepList[step].DurationMin;
double stepRuntime = stepDuration - stepTimeLeft;
double pStep = Math.Min(100, Math.Floor(stepRuntime / stepDuration * 100));
double testRunTime = (_dtTestStart - DateTime.Now).TotalMinutes;
double pTest = Math.Min(100, Math.Floor(testRunTime / _Profile.DurationMin * 100));
double testTimeRemain = _Profile.DurationMin - testRunTime;
double testTimeRemainHrs = Math.Floor(testTimeRemain / 60);
double testTimeRemainMin = Math.Floor(testTimeRemain - 60 * testTimeRemainHrs);
string progress = String.Format("Step #{0:00}/{1:00} progress {2:0}%, ", step + 1, _Profile.SerializedStepList.Count, pStep);
progress += String.Format("remaining step time {0:0}h{1:00}m, remaining cycles {2:0}, ",hrs,min, cyclesLeft);
progress += String.Format("test progress {0:0}%, remaining test time {1:0}h{2:00}m", pTest, testTimeRemainHrs,testTimeRemainMin);
return progress;
}
private bool TxRxSucces(string cmd, string read)
{
// Command not correctly processed
if (read.StartsWith("NA:"))
return false;
// No response received
if (read.Trim().Length < 1)
return false;
// Handle monitoring commands
if (cmd.Trim().Contains("?"))
{
return true;
}
else
{
if(read.Trim().Contains("OK:"))
return true;
}
return false;
}
// Performs transfer and adds interface logs to list in Client parent class
private Boolean DataTransfer(string cmd, out string read, int ReturnDataWaitms)
{
// If no maximum number of attempts is given, it defaults to 3.
return DataTransfer(cmd, out read, ReturnDataWaitms, 3);
}
// Performs transfer and adds interface logs to list in Client parent class
private Boolean DataTransfer(string cmd, out string read, int ReturnDataWaitms, int MaxNumOfAttempts)
{
// Construct command to send
cmd += (char)13; // CR
cmd += (char)10; // LF
cmd = cmd.Replace(" ", "");
// Wait for _ReadyToSend or max 2 seconds
DateTime go = DateTime.Now.AddSeconds(2);
while (DateTime.Now < _ReadyToSend && DateTime.Now < go)
System.Threading.Thread.Sleep(10);
read = "";
bool success = false;
int attempts = 0;
while (!success && attempts <= MaxNumOfAttempts)
{
DataTransferLog log = _Interface.DataTransfer(cmd, out read, ReturnDataWaitms);
success = TxRxSucces(cmd, read);
attempts++;
// Mask for showing in GUI
if (cmd.Contains("MODE?") || cmd.Contains("MON?"))
log.ShowInGUI = false;
// Notify user via GUI of failed attempts
if (attempts > 1)
log.Command += string.Format(" [Attempt {0:0}]", attempts);
// Add to logs
AppendDataTransferLog(log);
// Set _ReadyToSend acc. manual specs
if (cmd.Contains("?"))
_ReadyToSend = DateTime.Now.AddMilliseconds(300);
else
_ReadyToSend = DateTime.Now.AddMilliseconds(1000);
// Sleeps
if (!success)
System.Threading.Thread.Sleep(3000); // Sleep 3 seconds before resending if failed
}
return success;
}
}
}

View File

@@ -0,0 +1,61 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{162E2D74-E197-4188-A3B2-B33B827CC519}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>LHL113</RootNamespace>
<AssemblyName>LHL113</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Client.LHL113.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Task.LHL113.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Models\Models.csproj">
<Project>{09375A4A-28B8-427B-853D-75C03A070728}</Project>
<Name>Models</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("LHL113")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Microsoft")]
[assembly: AssemblyProduct("LHL113")]
[assembly: AssemblyCopyright("Copyright © Microsoft 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("8354967d-1852-4e51-81c6-2cb820268198")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -0,0 +1,388 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ChamChat.Models;
namespace ChamChat
{
public class LHL113_Task : Task
{
public LHL113_Task(Client Client, Profile Profile)
: base(Client, Profile)
{
_Profile = Profile;
_Client = Client;
_SerSteps = _Profile.SerializedStepList;
}
private const Int32 PollingIntervalSeconds = 10;
private List<Step> _SerSteps;
// To do
public override Boolean IsControlledProgrammable(Profile profile)
{
#warning LHL113_Task to implement: IsControlledProgrammable(Profile profile)
return true;
_NewProfileDuration = 0;
_ProfileNumOfSerialSteps = 1;
List<Profile> profiles = new List<Profile>();
int k = 0;
while( k < _SerSteps.Count)
{
Profile p = GetProfile(k);
profiles.Add(p);
k += _ProfileNumOfSerialSteps;
}
// for (int i = 0; i < _SerSteps.Count; i++)
//profiles.Add(GetProfile(i));
foreach (Profile p in profiles)
if (!_Client.IsProgrammable(p))
return false;
// In cases below, overheat/overcool alarm will sound immediately.
// Limits can be set to 50 °C from temperature.
for (int i = 1; i < _SerSteps.Count; i++)
{
Step step1 = _SerSteps[i - 1];
Step step2 = _SerSteps[i];
if (step1.T < 40 && step2.T < 40)
if (step2.T > step1.T + 50)
return false;
if (step1.T > 40 && step2.T > 40)
if (step2.T < step1.T - 50)
return false;
}
return true;
}
protected override void ThreadStandAlone()
{
// Write profile
try
{
if (!_Client.WriteProfile(_Profile))
{
_Status = TaskStatus.Stopped;
return;
}
}
catch (Exception ex)
{
_Status = TaskStatus.ExceptionOccured;
_TaskProgress = string.Format("Client WriteProfile() exception: {0}", ex.Message);
return;
}
// Start client
try
{
if (!_Client.Start())
{
_Status = TaskStatus.Stopped;
return;
}
}
catch (Exception ex)
{
_Status = TaskStatus.ExceptionOccured;
_TaskProgress = string.Format("Client Start() exception: {0}", ex.Message);
return;
}
DateTime lastPolled = DateTime.Now;
while (_Status == TaskStatus.IsRunning)
{
// Poll only every 'PollingIntervalSeconds' seconds
if (DateTime.Now > lastPolled.AddSeconds(PollingIntervalSeconds))
{
// Is finished?
try
{
if (_Client.IsFinished())
{
_Status = TaskStatus.Finished;
continue;
}
}
catch { }
try
{
_TaskProgress = _Client.Progress();
}
catch
{
_TaskProgress = "Progress could not be retrieved from client.";
}
lastPolled = DateTime.Now;
}
System.Threading.Thread.Sleep(100);
if (_Status == TaskStatus.AbortRequested)
{
try
{
if (_Client.Stop())
_Status = TaskStatus.Aborted;
}
catch { }
}
_isKicking = true;
}
_isKicking = false;
}
private Double _NewProfileDuration = 0; // Duration of new profile in minutes
private int _ProfileNumOfSerialSteps = 1; // Number of steps from serial step list performed in new profile.
protected override void ThreadControlled()
{
Int32 iCurrentSerialStep = -1;
DateTime startOfCurrentProgram = new DateTime(1900, 1, 1);
DateTime endOfCurrentProgram = new DateTime(1900, 1, 1);
Step currentStep = _SerSteps[0];
DateTime lastPolled = DateTime.Now;
_NewProfileDuration = 0;
_ProfileNumOfSerialSteps = 1;
while (_Status == TaskStatus.IsRunning)
{
if (DateTime.Now > endOfCurrentProgram)
{
iCurrentSerialStep += _ProfileNumOfSerialSteps;
// Last step has been performed?
if (iCurrentSerialStep > _SerSteps.Count - 1)
{
_Client.Stop();
_Status = TaskStatus.Finished;
AddEventLog("Last step performed");
continue;
}
currentStep = _SerSteps[iCurrentSerialStep];
Profile newProfile = GetProfile(iCurrentSerialStep);
if (_ProfileNumOfSerialSteps > 1)
{
if(newProfile.Loops.Count == 1 )
AddEventLog("Program : " + string.Format("{0:0} serial steps, loop {1}", _ProfileNumOfSerialSteps, newProfile.Loops[0].ToString()));
else
AddEventLog("Program : " + string.Format("{0:0} serial steps, no loops", _ProfileNumOfSerialSteps));
}
else
AddEventLog("Single step : " + currentStep.ToString());
RestartClient(newProfile);
if (_Status != TaskStatus.IsRunning)
continue;
// Update variables
startOfCurrentProgram = DateTime.Now;
endOfCurrentProgram = DateTime.Now.AddMinutes(_NewProfileDuration);
lastPolled = DateTime.Now;
}
// Poll only every 'PollingIntervalSeconds' seconds
if (DateTime.Now > lastPolled.AddSeconds(PollingIntervalSeconds))
{
// Is finished?
try
{
if (_Client.IsFinished())
{
_Status = TaskStatus.Interrupted; // Profile did not finish, client did
continue;
}
}
catch { }
try
{
double taskRunTime = (DateTime.Now - _startThread).TotalMinutes;
double pTest = Math.Min(100, Math.Floor(taskRunTime / _Profile.DurationMin * 100));
double stepRuntime = (DateTime.Now - startOfCurrentProgram).TotalMinutes;
double pStep = Math.Min(100,Math.Floor(stepRuntime / _NewProfileDuration * 100));
double taskTimeRemain = _Profile.DurationMin - taskRunTime;
double taskTimeRemainHrs = Math.Floor(taskTimeRemain / 60);
double taskTimeRemainMin = Math.Floor(taskTimeRemain - 60 * taskTimeRemainHrs);
_TaskProgress = String.Format("Step #{0:00}/{1:00} progress {2:0}%, test progress {3:0}%, remaining test time {4:0}h{5:00}m", iCurrentSerialStep + 1, _Profile.SerializedStepList.Count, pStep, pTest, taskTimeRemainHrs, taskTimeRemainMin);
}
catch
{
_TaskProgress = "Progress could not be calculated.";
}
lastPolled = DateTime.Now;
}
System.Threading.Thread.Sleep(200);
if (_Status == TaskStatus.AbortRequested)
{
try
{
if (_Client.Stop())
_Status = TaskStatus.Aborted;
}
catch { }
}
_isKicking = true;
}
_isKicking = false;
}
private void RestartClient(Profile newProfile)
{
// Stop client
try
{
if (!_Client.Stop())
{
_Status = TaskStatus.Interrupted;
return;
}
}
catch (Exception ex)
{
_Status = TaskStatus.ExceptionOccured;
_TaskProgress = string.Format("Client Stop() exception: {0}", ex.Message);
AddEventLog(_TaskProgress);
return;
}
System.Threading.Thread.Sleep(1000);
// Wait to finish
try
{
Boolean timedOut = true;
DateTime startWait = DateTime.Now;
while (DateTime.Now < startWait.AddSeconds(60))
{
System.Threading.Thread.Sleep(1000);
if (_Client.IsFinished())
{
timedOut = false;
break;
}
}
if (timedOut)
{
_Status = TaskStatus.Interrupted;
AddEventLog("Time out (60 s) in RestartClient.WaitForFinish");
return;
}
}
catch (Exception ex)
{
_Status = TaskStatus.ExceptionOccured;
_TaskProgress = string.Format("Client WaitForFinish exception: {0}", ex.Message);
AddEventLog(_TaskProgress);
return;
}
// Write profile
try
{
if (!_Client.WriteProfile(newProfile))
{
_Status = TaskStatus.Interrupted;
return;
}
}
catch (Exception ex)
{
_Status = TaskStatus.ExceptionOccured;
_TaskProgress = string.Format("Client WriteProfile() exception: {0}", ex.Message);
AddEventLog(_TaskProgress);
return;
}
// Start client
try
{
//AddEventLog("RestartClient.Start");
if (!_Client.Start())
{
_Status = TaskStatus.Interrupted;
return;
}
}
catch (Exception ex)
{
_Status = TaskStatus.ExceptionOccured;
_TaskProgress = string.Format("Client Start() exception: {0}", ex.Message);
AddEventLog(_TaskProgress);
return;
}
}
private Profile GetProfile(int iStep)
{
Step step = _SerSteps[iStep].DeepClone();
// Duration of programmed step is 15 minutes longer than profile
step.DurationMin += 15;
_NewProfileDuration = _SerSteps[iStep].DurationMin;
_ProfileNumOfSerialSteps = 1;
List<Step> steps = new List<Step>();
steps.Add(step);
// Loops
List<Loop> loops = new List<Loop>();
// Options
List<ProfileOption> options = new List<ProfileOption>();
options.Add(ProfileOption.LHL113_EndModeOff); // Shut down client for safety
// Create profile
return new Profile(_Profile.Title, steps, loops, options);
}
}
}

View File

@@ -0,0 +1,4 @@
// <autogenerated />
using System;
using System.Reflection;
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.0", FrameworkDisplayName = ".NET Framework 4")]

View File

@@ -0,0 +1 @@
ae4a20f7096bc6f8a600f5bcf410b2ab95b95f6c

View File

@@ -0,0 +1,2 @@
\\silicium\software\MASER software\Source\ChamChat\Client_LHL113\obj\Release\Client_LHL113.csproj.AssemblyReference.cache
\\silicium\software\MASER software\Source\ChamChat\Client_LHL113\obj\Release\Client_LHL113.csproj.CoreCompileInputs.cache

View File

@@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ChamChat.Models;
namespace ChamChat
{
public partial class PLxKPH_Client : Client
{
// Run a single step.
// The last setting is held when the program ends.
// See page 60.
public Boolean Start(Double DurationMin, Double StartT, Double TargetT, Double StartRH, Double TargetRH )
{
// Example: RUN PRGM, TEMP10.0 GOTEMP23.0 HUMI85 GOHUMI100 TIME1:00
string sAddr = _Address.ToString();
string cmd;
string read;
cmd = sAddr + ", RUN PRGM, ";
cmd += string.Format("TEMP{0:0.0} ", StartT);
if (StartT != TargetT) // Ramping required
cmd += string.Format("GOTEMP{0:0.0} ", TargetT);
if (TargetRH > 0)
{
cmd += string.Format("HUMI{0:0} ", StartRH);
if (StartRH != TargetRH) // Ramping required
cmd += string.Format("GOHUMI{0:0} ", TargetRH);
}
else cmd += "HUMI OFF "; // No RH set
double hrs = Math.Floor(DurationMin/60);
double min = Math.Floor(DurationMin - hrs * 60);
cmd += String.Format("TIME{0:0}:{1:0}", hrs, min);
return DataTransfer(cmd, out read, _ReturnDataWaitms);
}
}
}

View File

@@ -0,0 +1,384 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ChamChat.Models;
namespace ChamChat
{
public partial class PLxKPH_Client : Client
{
private const Int32 _OptionRange = 2000;
private const int _RAM = 1;
private const Int32 _ReturnDataWaitms = 300; // Time out for client to prepare and return data
private DateTime _ReadyToSend = DateTime.Now; // Timestamp when client is ready to communicate
public PLxKPH_Client(Int32 MIDS, ClientType Type)
: base(MIDS, Type)
{
// Set options available in client
_Parameters = new List<Parameter>();
_Parameters.Add(Parameter.T);
_Parameters.Add(Parameter.RH);
_Parameters.Add(Parameter.RampT);
_Parameters.Add(Parameter.RampRH);
// Add option range
_ClientOptions = new List<ProfileOption>();
foreach (ProfileOption o in Enum.GetValues(typeof(ProfileOption)))
if ((int)o >= _OptionRange && (int)o < _OptionRange + 999)
_ClientOptions.Add(o);
// Set availabel addresses for programming
_AvailableRAMs = new List<int>();
for (int i = 1; i < 21; i++)
_AvailableRAMs.Add(i);
_InterfaceType = InterfaceType.FDTI_USB_COM422;
}
// To do
public override Profile ReadProfile(int RAM, ref System.ComponentModel.BackgroundWorker bgw)
{
Profile profile = new Profile();
return profile;
}
public override Boolean WriteProfile(Profile profile)
{
return WriteProfile(profile, _RAM);
}
public override Boolean WriteProfile(Profile profile, int RAM)
{
// Only stand alone profiles allowed!
if( !IsProgrammable(profile))
return false;
string title = profile.Title.Substring(0, (int)Math.Min(14, profile.Title.Length)).Trim();
string sRAM = string.Format("{0:0}", RAM);
string sAddr = _Address.ToString();
string cmd;
string read;
string cmd_pre = sAddr + ", PRGM DATA WRITE, PGM" + sRAM + ", ";
// Cancel RAM program editing
cmd = cmd_pre + "EDIT CANCEL";
DataTransfer(cmd, out read, _ReturnDataWaitms,1);
if( !read.Contains("ERR-3"))
DataTransfer(cmd, out read, _ReturnDataWaitms, 3);
// Open RAM program
cmd = cmd_pre + "EDIT START";
DataTransfer(cmd,out read, _ReturnDataWaitms);
// Steps
try
{
for (int i = 0; i < profile.Steps.Count; i++)
{
Step step = profile.Steps[i];
cmd = cmd_pre;
cmd += String.Format("STEP{0:0}, ", i + 1);
cmd += String.Format("TEMP{0:0.0}, ", step.T);
cmd += step.RampCtrlT ? "TRAMPON, " : "TRAMPOFF, ";
cmd += step.HasRH ? String.Format("HUMI{0:0}, ", step.RH) : "HUMI OFF, ";
cmd += step.RampCtrlRH ? "HRAMPON, " : "HRAMPOFF, ";
cmd += String.Format("TIME{0:00}:{1:00}, ", step.Hours, step.Minutes);
cmd += "GRANTY OFF, ";
cmd += "PAUSE OFF";
DataTransfer(cmd, out read, _ReturnDataWaitms);
}
}
catch (Exception ex) { throw new Exception("writing steps - " + ex.Message); }
try
{
// Loops
if (profile.Loops.Count > 0)
{
Loop loop = profile.Loops[0];
cmd = cmd_pre;
cmd += String.Format("COUNT, A({0}.{1}.{2})", loop.N - 1, loop.Last + 1, loop.First + 1);
if (profile.Loops.Count > 1)
{
loop = profile.Loops[1];
cmd += String.Format(", B({0}.{1}.{2})", loop.N - 1, loop.Last + 1, loop.First + 1);
}
DataTransfer(cmd, out read, _ReturnDataWaitms);
}
}
catch (Exception ex) { throw new Exception("writing loops - " + ex.Message); }
// End mode
try
{
cmd = profile.Options.Contains(ProfileOption.PLxKPH_EndModeHold) ? cmd_pre + "END, HOLD" : cmd_pre + "END, OFF";
DataTransfer(cmd, out read, _ReturnDataWaitms);
}
catch (Exception ex) { throw new Exception("writing end mode - " + ex.Message); }
// Name of program
cmd = cmd_pre + "NAME, " + title;
DataTransfer(cmd, out read, _ReturnDataWaitms);
// Close and save RAM program
cmd = cmd_pre + "EDIT END";
DataTransfer(cmd, out read, _ReturnDataWaitms);
// Wait 3 seconds to close program
System.Threading.Thread.Sleep(3000);
Boolean result = false;
if (_Interface.InterfaceStatus == null)
result = true;
_Profile = profile;
return result;
}
public override Boolean IsProgrammable(Profile profile)
{
// Profile is programmable if all below applies
// number of profile steps 99
// number of loops < 3
// -40 < t < 150
if(profile.Steps.Count > 99)
return false;
if (profile.Loops.Count > 2)
return false;
foreach (Loop loop in profile.Loops)
if (loop.N > 99 || loop.N < 2)
return false;
foreach (Step step in profile.Steps)
{
if (step.T < -40 || step.T > 150)
return false;
}
return true;
}
public override Boolean HasAlarm(out List<Alarm> alarms)
{
alarms = new List<Alarm>();
return true;
}
public override Boolean IsIdle()
{
// IsIdle() returns true if status of chamber is 'Standby'. See page 36 MODE?.
string sAddr = _Address.ToString();
string cmd;
string read;
cmd = sAddr + ", MODE?";
DataTransfer(cmd,out read, _ReturnDataWaitms);
if (read.Contains("STANDBY"))
return true;
return false;
}
public override Boolean Start()
{
if (_Profile == null)
return false;
string sAddr = _Address.ToString();
string cmd;
string read;
cmd = sAddr + ", PRGM, RUN, RAM:" + _RAM+", STEP1"; // See page 56
return DataTransfer(cmd,out read, _ReturnDataWaitms);
}
public override Boolean IsFinished()
{
// Finished() returns true if chamber is not running. See page 36 MODE?.
string sAddr = _Address.ToString();
string cmd;
string read;
cmd = sAddr + ", MON?";
DataTransfer(cmd, out read, _ReturnDataWaitms);
try
{
double t = Double.Parse(read.Split(',')[0]);
double RH = Double.Parse(read.Split(',')[1]);
_Progress = String.Format("Current conditions are {0:0.0} °C and {1:0} %rh", t, RH);
_LastProgressUpdate = DateTime.Now;
}
catch { _Progress = DateTime.Now.ToString("yyyy-MM-dd @ hh:mm"); }
if (read.Contains("STANDBY"))
return true;
if (read.Contains("OFF"))
return true;
return false;
}
public override Boolean Stop()
{
string sAddr = _Address.ToString();
string cmd;
string read;
cmd = sAddr + ", MODE, STANDBY";
return DataTransfer(cmd, out read, _ReturnDataWaitms);
}
public override Boolean IsOnline()
{
try
{
string sAddr = _Address.ToString();
string cmd;
string read;
cmd = sAddr + ", TYPE?";
DataTransfer(cmd, out read, _ReturnDataWaitms);
return (read.ToLower().Contains("scp220") );
}
catch
{
return false;
}
}
private string _Progress = "";
private DateTime _LastProgressUpdate = DateTime.Now;
public override String Progress()
{
if(_LastProgressUpdate.AddMinutes(3) < DateTime.Now)
IsFinished();
return _Progress;
}
private bool TxRxSucces(string cmd, string read)
{
// Command not correctly processed
if (read.StartsWith("NA:"))
return false;
// No response received
if (read.Trim().Length < 1)
return false;
// Handle monitoring commands
if (cmd.Trim().Contains("?"))
{
return true;
}
else
{
if (read.Trim().StartsWith("OK:"))
return true;
}
return false;
}
private Boolean DataTransfer(string cmd, out string read, int ReturnDataWaitms)
{
// If no maximum number of attempts is given, it defaults to 4.
return DataTransfer(cmd, out read, ReturnDataWaitms,4);
}
// Performs transfer and adds interface logs to list in Client parent class
private Boolean DataTransfer(string cmd, out string read, int ReturnDataWaitms, int MaxNumOfAttempts)
{
// Construct command to send
cmd += (char)13; // CR
cmd += (char)10; // LF
cmd = cmd.Replace(" ", "");
// Wait for _ReadyToSend or max 1 seconds
DateTime go = DateTime.Now.AddSeconds(1);
while (DateTime.Now < _ReadyToSend && DateTime.Now < go)
System.Threading.Thread.Sleep(10);
read = "";
bool success = false;
int attempt = 0;
while (!success && attempt < MaxNumOfAttempts)
{
DataTransferLog log = _Interface.DataTransfer(cmd, out read, ReturnDataWaitms);
success = TxRxSucces(cmd, read);
attempt++;
// Mask for showing in GUI
if (cmd.Contains("MON?") || cmd.Contains("EDIT CANCEL") || cmd.Contains("EDITCANCEL"))
log.ShowInGUI = false;
// Notify user via GUI of failed attempts
if (attempt > 1)
log.Command += string.Format(" [Attempt {0:0}]", attempt);
// Add to logs
AppendDataTransferLog(log);
// Set _ReadyToSend acc. manual specs
if (cmd.Contains("?"))
_ReadyToSend = DateTime.Now.AddMilliseconds(500);
else
_ReadyToSend = DateTime.Now.AddMilliseconds(1200);
// Sleeps
if (!success)
System.Threading.Thread.Sleep(5000); // Sleep 5 seconds before resending if failed
}
return success;
}
}
}

View File

@@ -0,0 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{1FB70C9C-6F0B-4580-9682-A85B40C90B38}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>ChamChat</RootNamespace>
<AssemblyName>PLxKPH</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Client.PLxKPH.cs" />
<Compile Include="Client.PLxKPH.Specific.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Task.PLxKPH.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Models\Models.csproj">
<Project>{09375A4A-28B8-427B-853D-75C03A070728}</Project>
<Name>Models</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -0,0 +1,20 @@

Microsoft Visual Studio Solution File, Format Version 11.00
# Visual C# Express 2010
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Client_PLxKPH", "Client_PLxKPH.csproj", "{1FB70C9C-6F0B-4580-9682-A85B40C90B38}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1FB70C9C-6F0B-4580-9682-A85B40C90B38}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1FB70C9C-6F0B-4580-9682-A85B40C90B38}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1FB70C9C-6F0B-4580-9682-A85B40C90B38}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1FB70C9C-6F0B-4580-9682-A85B40C90B38}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

Binary file not shown.

View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("TSD100S")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Microsoft")]
[assembly: AssemblyProduct("TSD100S")]
[assembly: AssemblyCopyright("Copyright © Microsoft 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("2fc0fe7d-2c1d-4983-a44a-6c1fd33288e3")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -0,0 +1,347 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ChamChat.Models;
namespace ChamChat
{
public class PLxKPH_Task : Task
{
public PLxKPH_Task(Client Client, Profile Profile)
: base(Client, Profile)
{
_Profile = Profile;
_Client = Client;
_SerSteps = _Profile.SerializedStepList;
}
private const Int32 PollingIntervalSeconds = 10;
private List<Step> _SerSteps;
public override Boolean IsControlledProgrammable(Profile profile)
{
ClientMessage msg = new ClientMessage(String.Format("The {0} can only operate in stand alone mode.", _Client.TypeDescription));
_Client.ClientMessages = new List<ClientMessage>();
_Client.ClientMessages.Add(msg);
return false;
}
protected override void ThreadStandAlone()
{
// Write profile
try
{
if (!_Client.WriteProfile(_Profile))
{
_Status = TaskStatus.Stopped;
return;
}
}
catch (Exception ex)
{
_Status = TaskStatus.ExceptionOccured;
_TaskProgress = string.Format("Client WriteProfile() exception: {0}", ex.Message);
return;
}
// Start client
try
{
if (!_Client.Start())
{
_Status = TaskStatus.Stopped;
return;
}
}
catch (Exception ex)
{
_Status = TaskStatus.ExceptionOccured;
_TaskProgress = string.Format("Client Start() exception: {0}", ex.Message);
return;
}
DateTime lastPolled = DateTime.Now;
while (_Status == TaskStatus.IsRunning)
{
// Poll only every 'PollingIntervalSeconds' seconds
if (DateTime.Now > lastPolled.AddSeconds(PollingIntervalSeconds))
{
// Is finished?
try
{
if (_Client.IsFinished())
{
_Status = TaskStatus.Finished;
continue;
}
}
catch { }
try
{
// Client return "Current conditions are x °C and x %rh"
_TaskProgress = _Client.Progress();
double runTimeMin = (DateTime.Now - StartOfTask).TotalMinutes;
double p = runTimeMin / _Profile.DurationMin * 100;
double remainTimeMin = Math.Max(0,_Profile.DurationMin - runTimeMin);
double hrs = Math.Floor(remainTimeMin /60);
double min = Math.Floor(remainTimeMin - 60 * hrs);
_TaskProgress += String.Format(", {0:0.0}% completed, {1:0}h{2:00} remaining",p, hrs,min );
}
catch { }
lastPolled = DateTime.Now;
}
System.Threading.Thread.Sleep(100);
if (_Status == TaskStatus.AbortRequested)
{
try
{
if (_Client.Stop())
_Status = TaskStatus.Aborted;
}
catch { }
}
_isKicking = true;
}
_isKicking = false;
}
protected override void ThreadControlled()
{
Int32 iCurrentSerialStep = -1;
DateTime startOfCurrentProgram = new DateTime(1900, 1, 1);
DateTime endOfCurrentProgram = new DateTime(1900, 1, 1);
Step currentStep = _SerSteps[0];
DateTime lastPolled = DateTime.Now;
while (_Status == TaskStatus.IsRunning)
{
if (DateTime.Now > endOfCurrentProgram)
{
iCurrentSerialStep++;
// Last step has been performed?
if (iCurrentSerialStep > _SerSteps.Count - 1)
{
_Client.Stop();
_Status = TaskStatus.Finished;
AddEventLog("Last step performed");
continue;
}
// Get step details
currentStep = _SerSteps[iCurrentSerialStep];
double TargetT = currentStep.T;
double TargetRH = currentStep.RH;
double DurationMin = currentStep.DurationMin;
double StartT = currentStep.T; // Set start to be target, but change to value of previous step if ramped.
if (currentStep.RampCtrlT)
{
if (iCurrentSerialStep == 0)
StartT = 23;
else
StartT = _SerSteps[iCurrentSerialStep - 1].T;
}
double StartRH = currentStep.RH; // Set start to be target, but change to value of previous step if ramped.
if (currentStep.RampCtrlRH)
{
if (iCurrentSerialStep == 0)
StartRH = 60;
else
StartRH = _SerSteps[iCurrentSerialStep - 1].RH;
}
RestartClient(DurationMin, StartT, TargetT, StartRH, TargetRH);
if (_Status != TaskStatus.IsRunning)
continue;
// Update variables
startOfCurrentProgram = DateTime.Now;
endOfCurrentProgram = DateTime.Now.AddMinutes(DurationMin);
lastPolled = DateTime.Now;
#region Update events
try
{
string s = "Set conditions: ";
if (currentStep.RampCtrlT)
s += String.Format("to {0:0.0} °C ({1:0.00} ˜°C/min), ", TargetT, (TargetT - StartT) / DurationMin);
else
s += String.Format("{0:0.0} °C, ", TargetT);
if (currentStep.RampCtrlRH)
s += String.Format("to {0:0.0} %rh ({1:0.00} ˜%rh/min), ", TargetRH, (TargetRH - StartRH) / DurationMin);
else
s += String.Format("{0:0.0} %rh, ", TargetRH);
s += string.Format("{0:0}h{1:00}", currentStep.Hours, currentStep.Minutes);
AddEventLog(s);
s = string.Format("Partial profile end is {0:00}-{1:00} @ {2:00}:{3:00}:{4:00}", endOfCurrentProgram.Day, endOfCurrentProgram.Month, endOfCurrentProgram.Hour, endOfCurrentProgram.Minute, endOfCurrentProgram.Second);
AddEventLog(s);
}
catch (Exception ex) { AddEventLog("Update events: " + ex.Message); }
#endregion Update events
}
// Poll only every 'PollingIntervalSeconds' seconds
if (DateTime.Now > lastPolled.AddSeconds(PollingIntervalSeconds))
{
// Is finished?
try
{
if (_Client.IsFinished())
{
// Last step is held (page 61) when program ends. Client will never finish by itself.
AddEventLog("Client finished, but task did not!");
_Status = TaskStatus.Interrupted; // Profile did not finish, client did
continue;
}
}
catch { } // Always continue and keep trying
#region Taskprogress
try
{
double taskRunTime = (DateTime.Now - _startThread).TotalMinutes;
double pTest = Math.Min(100, Math.Floor(taskRunTime / _Profile.DurationMin * 100));
double taskTimeRemain = _Profile.DurationMin - taskRunTime;
double taskTimeRemainHrs = Math.Floor(taskTimeRemain / 60);
double taskTimeRemainMin = Math.Floor(taskTimeRemain - 60 * taskTimeRemainHrs);
double currentStepRuntime = (DateTime.Now - startOfCurrentProgram).TotalMinutes;
double pStep = Math.Min(100, Math.Floor(currentStepRuntime / currentStep.DurationMin * 100));
_TaskProgress = String.Format("Step #{0:0}/{1:0} progress {2:0}%, test progress {3:0}%, remaining test time {4:0}h{5:00}m", iCurrentSerialStep + 1,_SerSteps.Count, pStep, pTest, taskTimeRemainHrs, taskTimeRemainMin);
if (iCurrentSerialStep + 1 == _SerSteps.Count && pTest > 99.99)
_TaskProgress = "Profile executed";
}
catch { _TaskProgress = "n/a"; }
#endregion Taskprogress
lastPolled = DateTime.Now;
}
System.Threading.Thread.Sleep(200);
_isKicking = true;
}
if (_Status == TaskStatus.AbortRequested)
{
try
{
if (_Client.Stop())
_Status = TaskStatus.Aborted;
}
catch { }
}
_isKicking = false;
}
private void RestartClient(Double DurationMin, Double StartT, Double TargetT, Double StartRH, Double TargetRH)
{
// Stop client
try
{
AddEventLog("Info: Stopping client");
if (!_Client.Stop())
{
_Status = TaskStatus.Interrupted;
AddEventLog("Task interrupted while trying to stop client!");
return;
}
}
catch (Exception ex)
{
_Status = TaskStatus.ExceptionOccured;
_TaskProgress = string.Format("Client Stop() exception: {0}", ex.Message);
AddEventLog(_TaskProgress);
return;
}
// Wait to finish
try
{
Boolean timedOut = true;
DateTime startWait = DateTime.Now;
while (DateTime.Now < startWait.AddSeconds(60))
{
System.Threading.Thread.Sleep(1000);
if (_Client.IsFinished())
{
timedOut = false;
break;
}
}
if (timedOut)
{
_Status = TaskStatus.Interrupted;
AddEventLog("Time out (60 s) in RestartClient.WaitForFinish");
return;
}
}
catch (Exception ex)
{
_Status = TaskStatus.ExceptionOccured;
_TaskProgress = string.Format("Client WaitForFinish exception: {0}", ex.Message);
AddEventLog(_TaskProgress);
return;
}
AddEventLog("Info: Client stopped");
// Start client
try
{
AddEventLog("Info: Starting client");
if (!((PLxKPH_Client)_Client).Start(DurationMin, StartT, TargetT, StartRH, TargetRH))
{
// Try to start again after 10 sec
AddEventLog("First attempt to start client failed!");
System.Threading.Thread.Sleep(10000);
if (!((PLxKPH_Client)_Client).Start(DurationMin, StartT, TargetT, StartRH, TargetRH))
{
_Status = TaskStatus.Interrupted;
AddEventLog("Task interrupted while trying to start client!");
return;
}
}
}
catch (Exception ex)
{
_Status = TaskStatus.ExceptionOccured;
_TaskProgress = string.Format("Client Start() exception: {0}", ex.Message);
AddEventLog(_TaskProgress);
return;
}
AddEventLog("Info: Client started");
}
}
}

View File

@@ -0,0 +1,4 @@
// <autogenerated />
using System;
using System.Reflection;
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.0", FrameworkDisplayName = ".NET Framework 4")]

View File

@@ -0,0 +1 @@
030d805dcba3c63f1b65d4f63d5ddc35bc93310a

View File

@@ -0,0 +1,2 @@
\\silicium\software\MASER software\Source\ChamChat\Client_PLxKPH\obj\Release\Client_PLxKPH.csproj.AssemblyReference.cache
\\silicium\software\MASER software\Source\ChamChat\Client_PLxKPH\obj\Release\Client_PLxKPH.csproj.CoreCompileInputs.cache

View File

@@ -0,0 +1,151 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ChamChat
{
public partial class TSx_Client : Client
{
public bool ShiftToA()
{
string sAddr = _Address.ToString();
string cmd;
string read;
cmd = sAddr + ", TAREA?";
DataTransfer(cmd, out read, _ReturnDataWaitms);
// If moving, wait to finish
if (read.Contains("MOVE"))
{
bool moving = true;
while (moving)
{
System.Threading.Thread.Sleep(2000);
DataTransfer(cmd, out read, _ReturnDataWaitms);
if (!read.Contains("MOVE"))
moving = false;
}
}
// Already in Cold
if (read.Contains("C"))
return true;
cmd = sAddr + ", MODE, TAREAMOVE";
DataTransfer(cmd, out read, _ReturnDataWaitms);
System.Threading.Thread.Sleep(5000); // Wait for move to finish
cmd = sAddr + ", TAREA?";
DataTransfer(cmd, out read, _ReturnDataWaitms);
// If moving, wait to finish
if (read.Contains("MOVE"))
{
bool moving = true;
while (moving)
{
System.Threading.Thread.Sleep(2000);
DataTransfer(cmd, out read, _ReturnDataWaitms);
if (!read.Contains("MOVE"))
moving = false;
}
}
// Already in Cold
if (read.Contains("C"))
return true;
// Not in Cold, not moving towards cold
return false;
}
public bool ShiftToB()
{
string sAddr = _Address.ToString();
string cmd;
string read;
cmd = sAddr + ", TAREA?";
DataTransfer(cmd, out read, _ReturnDataWaitms);
// If moving, wait to finish
if (read.Contains("MOVE"))
{
bool moving = true;
while (moving)
{
System.Threading.Thread.Sleep(2000);
DataTransfer(cmd, out read, _ReturnDataWaitms);
if (!read.Contains("MOVE"))
moving = false;
}
}
// Already in Hot
if (read.Contains("H"))
return true;
cmd = sAddr + ", MODE, TAREAMOVE";
DataTransfer(cmd, out read, _ReturnDataWaitms);
System.Threading.Thread.Sleep(5000); // Wait for move to finish
cmd = sAddr + ", TAREA?";
DataTransfer(cmd, out read, _ReturnDataWaitms);
// If moving, wait to finish
if (read.Contains("MOVE"))
{
bool moving = true;
while (moving)
{
System.Threading.Thread.Sleep(2000);
DataTransfer(cmd, out read, _ReturnDataWaitms);
if (!read.Contains("MOVE"))
moving = false;
}
}
// In Hot
if (read.Contains("H"))
return true;
// Not in Hot, not moving towards Hot
return false;
}
public Boolean AwaitMoving(Int32 timeOutSec)
{
string sAddr = _Address.ToString();
string cmd = sAddr + ", TAREA?";;
string read;
DateTime dtTimeOut = DateTime.Now.AddSeconds(timeOutSec);
while (DateTime.Now < dtTimeOut)
{
DataTransfer(cmd, out read, _ReturnDataWaitms);
if (!read.Contains("MOVE"))
return true;
System.Threading.Thread.Sleep(2000);
}
return false;
}
public Double CurrentTemperature()
{
string sAddr = _Address.ToString();
string cmd;
string read;
cmd = sAddr + ", TEMP?"; // See page 36
DataTransfer(cmd, out read, _ReturnDataWaitms,1);
return Double.Parse(read.Split(',')[6]);
}
}
}

View File

@@ -0,0 +1,724 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ChamChat.Models;
namespace ChamChat
{
public partial class TSx_Client : Client
{
private const Int32 _OptionRange = 1000;
//private const string _RAM = "RAM:20";
private const int _RAM = 20;
private const Int32 _ReturnDataWaitms = 300; // Time out for client to prepare and return data
private DateTime _ReadyToSend = DateTime.Now; // Timestamp when client is ready to communicate
public TSx_Client(Int32 MIDS, ClientType Type)
: base(MIDS, Type)
{
// Set options available in client
_Parameters = new List<Parameter>();
_Parameters.Add(Parameter.T);
_Parameters.Add(Parameter.PreTemp);
_Parameters.Add(Parameter.Tlimit);
_Parameters.Add(Parameter.ProceedWithNextStep);
// Add option range
_ClientOptions = new List<ProfileOption>();
foreach (ProfileOption o in Enum.GetValues(typeof(ProfileOption)))
if ((int)o >= _OptionRange && (int)o < _OptionRange + 999)
_ClientOptions.Add(o);
// Set availabel addresses for programming
_AvailableRAMs = new List<int>();
for (int i = 1; i < 31; i++)
_AvailableRAMs.Add(i);
_InterfaceType = InterfaceType.FDTI_USB_COM422;
}
public override Profile ReadProfile(int RAM, ref System.ComponentModel.BackgroundWorker bgw)
{
string sAddr = _Address.ToString();
string cmd;
string read;
string ram = string.Format("RAM:{0:00}", RAM);
// Communicate with client
cmd = sAddr + ",PRGMREAD," + ram;
DataTransfer(cmd, out read, _ReturnDataWaitms, 1);
bgw.ReportProgress(8);
cmd = sAddr + ",LISTTEMP?";
if (!bgw.CancellationPending)
DataTransfer(cmd, out read, _ReturnDataWaitms, 1);
string LISTTEMP = read;
bgw.ReportProgress(16);
cmd = sAddr + ",LISTPREAI?";
if (!bgw.CancellationPending)
DataTransfer(cmd, out read, _ReturnDataWaitms, 1);
string LISTPREAI = read;
bgw.ReportProgress(24);
cmd = sAddr + ",LISTPRE?";
if (!bgw.CancellationPending)
DataTransfer(cmd, out read, _ReturnDataWaitms, 1);
string LISTPRE = read;
bgw.ReportProgress(32);
cmd = sAddr + ",LISTTIME?";
if (!bgw.CancellationPending)
DataTransfer(cmd, out read, _ReturnDataWaitms, 1);
string LISTTIME = read;
bgw.ReportProgress(40);
cmd = sAddr + ",LISTCYCLE?";
if (!bgw.CancellationPending)
DataTransfer(cmd, out read, _ReturnDataWaitms, 1);
string LISTCYCLE = read;
bgw.ReportProgress(48);
cmd = sAddr + ",LISTSTARTPOSITION?";
if (!bgw.CancellationPending)
DataTransfer(cmd, out read, _ReturnDataWaitms, 1);
string LISTSTARTPOSITION = read;
bgw.ReportProgress(56);
cmd = sAddr + ",LISTEND?";
if (!bgw.CancellationPending)
DataTransfer(cmd, out read, _ReturnDataWaitms, 1);
string LISTEND = read;
bgw.ReportProgress(64);
cmd = sAddr + ",LISTNAME?";
if (!bgw.CancellationPending)
DataTransfer(cmd, out read, _ReturnDataWaitms, 1);
string LISTNAME = read;
bgw.ReportProgress(72);
cmd = sAddr + ",LISTSENSOR?";
if (!bgw.CancellationPending)
DataTransfer(cmd, out read, _ReturnDataWaitms, 1); // Not used in software.
string LISTSENSOR = read;
bgw.ReportProgress(80);
cmd = sAddr + ",LISTTEMPLIMIT?";
if (!bgw.CancellationPending)
DataTransfer(cmd, out read, _ReturnDataWaitms, 1);
string LISTTEMPLIMIT = read;
bgw.ReportProgress(88);
// 01728 test
// 4,PRGMREAD,RAM:20
// 4,LISTTEMPLIMIT?
// 4,PRGMREADEND
cmd = sAddr + ",PRGMREADEND";
DataTransfer(cmd, out read, _ReturnDataWaitms, 1);
bgw.ReportProgress(96);
Profile profile = new Profile();
// Cancel read out
if (bgw.CancellationPending)
{
profile.Title = "Cancelled";
return profile;
}
try
{
// High temperature
double TB = Double.Parse(LISTTEMP.Split(',')[0]);
string tB = LISTTIME.Split(',')[1].Trim();
double hrsB = Double.Parse(tB.Split(':')[0]);
double minB = Double.Parse(tB.Split(':')[1]);
double preTB = Double.Parse(LISTPRE.Split(',')[0]);
double HL = Double.Parse(LISTTEMPLIMIT.Split(',')[0]);
// Low temperature
double TA = Double.Parse(LISTTEMP.Split(',')[1]);
string tA = LISTTIME.Split(',')[2].Trim();
double hrsA = Double.Parse(tA.Split(':')[0]);
double minA = Double.Parse(tA.Split(':')[1]);
double preTA = Double.Parse(LISTPRE.Split(',')[1]);
double LL = Double.Parse(LISTTEMPLIMIT.Split(',')[1]);
// Number of cycles
Int32 numOfCycles = Int32.Parse(LISTCYCLE);
// Name
String name = LISTNAME;
// Options: page 44 & 72
List<ProfileOption> options = new List<ProfileOption>();
if (LISTPREAI == "ON")
options.Add(ProfileOption.TSx_PreTempAuto);
else
options.Add(ProfileOption.TSx_PreTempManual);
switch (LISTEND)
{
case "HEATRETURN":
options.Add(ProfileOption.TSx_EndModeHeatReturn);
break;
case "SETUP":
options.Add(ProfileOption.TSx_EndModeSetup);
break;
case "DEFROST":
options.Add(ProfileOption.TSx_EndModeDefrost);
break;
case "DRY":
options.Add(ProfileOption.TSx_EndModeDry);
break;
default:
options.Add(ProfileOption.TSx_EndModeOff);
break;
}
Step B = new Step(hrsB * 60 + minB);
B.T = TB;
B.PreTemp = preTB;
B.LimitT = HL;
Step A = new Step(hrsA * 60 + minA);
A.T = TA;
A.PreTemp = preTA;
A.LimitT = LL;
List<Step> steps = new List<Step>();
// If test should start in high, then start with B
if (LISTSTARTPOSITION == "H")
{
steps.Add(B);
steps.Add(A);
}
else
{
steps.Add(A);
steps.Add(B);
}
Loop loop = new Loop(numOfCycles, 0, 1);
List<Loop> loops = new List<Loop>();
loops.Add(loop);
// Create profile
profile = new Profile(name, steps, loops, options);
}
catch
{
}
return profile;
}
public override Boolean WriteProfile(Profile profile)
{
// Pass a dummy bacckgroundworker and the default RAM
return WriteProfile(profile, _RAM);
}
public override Boolean WriteProfile(Profile profile, int RAM)
{
// Pass a dummy bacckgroundworker with no event subscriptions
System.ComponentModel.BackgroundWorker bgw = new System.ComponentModel.BackgroundWorker();
return WriteProfile(profile, _RAM, ref bgw);
}
public override Boolean WriteProfile(Profile profile, int RAM, ref System.ComponentModel.BackgroundWorker bgw)
{
// Only stand alone profiles allowed!
if (!IsProgrammable(profile))
return false;
string title = profile.Title.Substring(0, (int)Math.Min(14, profile.Title.Length)).Trim();
string sAddr = _Address.ToString();
string cmd;
string read;
string ram = string.Format("RAM:{0:00}", RAM);
Step A, B; // A is low temperature step, B is high temperature step
string startPosition;
if (profile.Steps[0].T < profile.Steps[1].T)
{
A = profile.Steps[0];
B = profile.Steps[1];
startPosition = "L";
}
else
{
A = profile.Steps[1];
B = profile.Steps[0];
startPosition = "H";
}
#warning report Progress to bgw
bgw.ReportProgress(8);
// Communicate with client
cmd = sAddr + ", PRGMWRITE," + ram;
if (!bgw.CancellationPending)
DataTransfer(cmd, out read, _ReturnDataWaitms);
// Name of program
cmd = sAddr + ", NAME, " + title;
if (!bgw.CancellationPending)
DataTransfer(cmd, out read, _ReturnDataWaitms);
// Temperatures
cmd = sAddr + ", TEMP, " + string.Format("S{0:000},{1:+#;-#00}", B.T, A.T);
if (A.T == 0)
cmd = sAddr + ", TEMP, " + string.Format("S{0:000}, 000", B.T);
if (!bgw.CancellationPending)
DataTransfer(cmd, out read, _ReturnDataWaitms);
// Preheat and precool
cmd = sAddr + ", PRE, " + string.Format("{0:000},{1:+#;-#00}", B.PreTemp, A.PreTemp);
if (A.PreTemp == 0)
cmd = sAddr + ", PRE, " + string.Format("{0:000}, 000", B.PreTemp);
if (!bgw.CancellationPending)
DataTransfer(cmd, out read, _ReturnDataWaitms);
// Dwell times
int hrsA = (int)Math.Floor(A.DurationMin / 60);
int minA = (int)Math.Floor(A.DurationMin - 60 * hrsA);
int hrsB = (int)Math.Floor(B.DurationMin / 60);
int minB = (int)Math.Floor(B.DurationMin - 60 * hrsB);
cmd = sAddr + ", TIME, " + string.Format("00:00, {0:00}:{1:00}, {2:00}:{3:00}", hrsB, minB, hrsA, minA);
if (!bgw.CancellationPending)
DataTransfer(cmd, out read, _ReturnDataWaitms);
// Start position
cmd = sAddr + ", STARTPOSITION, " + startPosition;
if (!bgw.CancellationPending)
DataTransfer(cmd, out read, _ReturnDataWaitms);
// Auto preheat/precool (default is manual): page 44 & 72
string preai = "OFF";
if (profile.Options.Contains(ProfileOption.TSx_PreTempAuto))
preai = "ON";
cmd = sAddr + ", PREAI, " + preai;
if (!bgw.CancellationPending)
DataTransfer(cmd, out read, _ReturnDataWaitms);
// Number of cycles
int numOfCycles = 1;
if (profile.Loops.Count > 0)
numOfCycles = profile.Loops[0].N;
cmd = sAddr + ", CYCLE, " + string.Format("{0:0000}", numOfCycles);
if (!bgw.CancellationPending)
DataTransfer(cmd, out read, _ReturnDataWaitms);
// End mode (default is off)
string end = "OFF";
if (profile.Options.Contains(ProfileOption.TSx_EndModeHeatReturn))
end = "HEATRETURN";
if (profile.Options.Contains(ProfileOption.TSx_EndModeSetup))
end = "SETUP";
if (profile.Options.Contains(ProfileOption.TSx_EndModeDefrost))
end = "DEFROST";
if (profile.Options.Contains(ProfileOption.TSx_EndModeDry))
end = "DRY";
cmd = sAddr + ", END, " + end;
if (!bgw.CancellationPending)
DataTransfer(cmd, out read, _ReturnDataWaitms);
// Overheat/Overcool protection
cmd = sAddr + ", TEMPLIMIT, " + string.Format("{0:000},{1:+#;-#00}", B.LimitT, A.LimitT);
if (A.LimitT == 0)
cmd = sAddr + ", TEMPLIMIT, " + string.Format("{0:000}, 000", B.LimitT);
if (!bgw.CancellationPending)
DataTransfer(cmd, out read, _ReturnDataWaitms);
// Always perform PRGMWRITEEND, also if bgw.CancellationPending
cmd = sAddr + ", PRGMWRITEEND," + ram;
DataTransfer(cmd, out read, _ReturnDataWaitms);
Boolean result = false;
if (_Interface.InterfaceStatus == null)
result = true;
_Profile = profile;
return result;
}
public override Boolean IsProgrammable(Profile profile)
{
// Profile is programmable if all below applies
// number of steps 2
// number of loops < 2
// number of cycles < 9999
// -77 < tA < 0
// 60 < tB < 205
// -77 < Pre-tA < 0
// 60 <Pre-tB < 205
// Limit overcool is 0..50 °C below tA
// Limit overheat is 0..50 °C above tB
// Ramp control not used
double[] preH = new double[2]{60,205};
double[] preC = new double[2] { -77, 0 };
double[] tB = new double[2] { 60, 205 };
double[] tA = new double[2] { -77, 0 };
// Specifics
if (_Type == ClientType.TSD100S)
{
preH[1] = 305;
tB[1] = 305;
}
if (_Type == ClientType.TSD100 && _MIDS == 1728)
{
preH[0] = 30;
tB[0] = 30;
}
if (_Type == ClientType.TSE11A)
{
preC[0] = -82;
}
foreach (Step step in profile.Steps)
if (step.RampCtrlT)
{
_ClientMessages.Add(new ClientMessage("Program cannot be written to client: ramp control must be off"));
return false;
}
if (profile.Steps.Count != 2)
{
_ClientMessages.Add(new ClientMessage("Program cannot be written to client: there must be 2 steps"));
return false;
}
if (profile.Loops.Count > 1)
return false;
if(profile.Loops.Count == 1)
if(profile.Loops[0].N > 9999)
{
_ClientMessages.Add(new ClientMessage("Program cannot be written to client: number of repeats must ben smaller than 9999"));
return false;
}
Step A, B; // A is low temperature step, B is high temperature step
if (profile.Steps[0].T < profile.Steps[1].T)
{
A = profile.Steps[0];
B = profile.Steps[1];
}
else
{
A = profile.Steps[1];
B = profile.Steps[0];
}
// Step A
if (A.PreTemp < preC[0] || A.PreTemp > preC[1])
{
string msg = string.Format("pre-cool must be in range {0:0} to {1:0} °C", preC[0] , preC[1]);
_ClientMessages.Add(new ClientMessage("Program cannot be written to client: "+msg));
return false;
}
if (A.T < tA[0] || A.T > tA[1])
{
string msg = string.Format("cold temperature must be in range {0:0} to {1:0} °C", tA[0], tA[1]);
_ClientMessages.Add(new ClientMessage("Program cannot be written to client: " + msg));
return false;
}
if (A.LimitT > A.T || A.LimitT < A.T-50)
{
string msg = string.Format("cold limit must be in range {0:0} to {1:0} °C", A.T - 50, A.T);
_ClientMessages.Add(new ClientMessage("Program cannot be written to client: " + msg));
return false;
}
// Step B
if (B.PreTemp < preH[0] || B.PreTemp > preH[1])
{
string msg = string.Format("pre-heat must be in range {0:0} to {1:0} °C", preH[0], preH[1]);
_ClientMessages.Add(new ClientMessage("Program cannot be written to client: " + msg));
return false;
}
if (B.T < tB[0] || B.T > tB[1])
{
string msg = string.Format("hot temperature must be in range {0:0} to {1:0} °C", tB[0], tB[1]);
_ClientMessages.Add(new ClientMessage("Program cannot be written to client: " + msg));
return false;
}
if (B.LimitT < B.T || B.LimitT > B.T +50)
{
string msg = string.Format("hot limit must be in range {0:0} to {1:0} °C", B.T, B.T + 50);
_ClientMessages.Add(new ClientMessage("Program cannot be written to client: " + msg));
return false;
}
return true;
}
public override Boolean HasAlarm(out List<Alarm> alarms)
{
alarms = new List<Alarm>();
return true;
}
public override Boolean IsIdle()
{
// IsIdle() returns true if status of chamber is 'Standby'. See page 34 MODE?.
string sAddr = _Address.ToString();
string cmd;
string read;
cmd = sAddr + ", MODE?";
DataTransfer(cmd,out read, _ReturnDataWaitms);
if (read.Contains("STANDBY"))
return true;
return false;
}
public override Boolean Start()
{
if (_Profile == null)
return false;
string sAddr = _Address.ToString();
string cmd;
string read;
// Clear number of remaining cycles
cmd = sAddr + ", OPECYCLERESET"; // See ASSIGN page 63
DataTransfer(cmd, out read, _ReturnDataWaitms,1);
string ram = string.Format("RAM:{0:00}", _RAM);
// Assign the profile
cmd = sAddr + ", ASSIGN, " + ram; // See ASSIGN page 66
if(!DataTransfer(cmd,out read, _ReturnDataWaitms))
return false;
if (_Profile.Options.Contains(ProfileOption.TSx_StartNoSetup))
cmd = sAddr + ", OPETEST"; // See page 61
else
cmd = sAddr + ", OPESETUPEND"; // See page 61
return DataTransfer(cmd,out read, _ReturnDataWaitms);
}
public override Boolean IsFinished()
{
// Finished() returns true if chamber is not running. See page 34 MODE?.
string sAddr = _Address.ToString();
string cmd;
string read;
cmd = sAddr + ", MODE?";
DataTransfer(cmd, out read, _ReturnDataWaitms);
if (read.Contains("POWER-OFF"))
return true;
if (read.Contains("STANDBY"))
return true;
if (read.Contains("END-SETUP"))
return true;
if (read.Contains("END-READY"))
return true;
if (read.Contains("END-OFF"))
return true;
return false;
}
public override Boolean Stop()
{
string sAddr = _Address.ToString();
string cmd;
string read;
cmd = sAddr + ", OPESTANDBY";
return DataTransfer(cmd, out read, _ReturnDataWaitms);
}
public override Boolean IsOnline()
{
try
{
string sAddr = _Address.ToString();
string cmd;
string read;
cmd = sAddr + ", MODEL?";
DataTransfer(cmd, out read, _ReturnDataWaitms);
return (read.ToLower().Contains("tsd") || read.ToLower().Contains("tse"));
}
catch
{
return false;
}
}
public override String Progress()
{
string sAddr = _Address.ToString();
string cmd;
string read;
cmd = sAddr + ", CYCLE?"; // See page 38
DataTransfer(cmd,out read, _ReturnDataWaitms,1);
Int32 n = Int32.Parse(read.Split(',')[0]);
Int32 N = Int32.Parse(read.Split(',')[1]);
double t = CurrentTemperature();
return String.Format("{0:0}/{1:0} cycles executed. Temperature is {2:0} °C", n, N, t);
}
private bool TxRxSucces(string cmd, string read)
{
// Command not correctly processed
if (read.StartsWith("NA:"))
return false;
// No response received
if (read.Trim().Length < 1)
return false;
// Handle monitoring commands
if (cmd.Trim().Contains("?"))
{
return true;
}
else
{
if (read.Trim().StartsWith("OK:"))
return true;
}
return false;
}
private Boolean DataTransfer(string cmd, out string read, int ReturnDataWaitms)
{
// If no maximum number of attempts is given, it defaults to 3.
return DataTransfer(cmd, out read, ReturnDataWaitms,3);
}
// Performs transfer and adds interface logs to list in Client parent class
private Boolean DataTransfer(string cmd, out string read, int ReturnDataWaitms, int MaxNumOfAttempts)
{
// Construct command to send
cmd += (char)13; // CR
cmd += (char)10; // LF
cmd = cmd.Replace(" ", "");
// Wait for _ReadyToSend or max 1 seconds
DateTime go = DateTime.Now.AddSeconds(1);
while (DateTime.Now < _ReadyToSend && DateTime.Now < go)
System.Threading.Thread.Sleep(10);
read = "";
bool success = false;
int attempts = 0;
while (!success && attempts <= MaxNumOfAttempts)
{
DataTransferLog log = _Interface.DataTransfer(cmd, out read, ReturnDataWaitms);
success = TxRxSucces(cmd, read);
attempts++;
// Mask for showing in GUI
if (cmd.Contains("MODE?") || cmd.Contains("CYCLE?"))
log.ShowInGUI = false;
// Notify user via GUI of failed attempts
if (attempts > 1)
log.Command += string.Format(" [Attempt {0:0}]", attempts);
// Add to logs
AppendDataTransferLog(log);
// Set _ReadyToSend acc. manual specs
if (cmd.Contains("?"))
_ReadyToSend = DateTime.Now.AddMilliseconds(300);
else
_ReadyToSend = DateTime.Now.AddMilliseconds(1000);
// Sleeps
if (!success)
System.Threading.Thread.Sleep(3000); // Sleep 3 seconds before resending if failed
}
return success;
}
}
}

View File

@@ -0,0 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{A863C309-E15C-4EA1-82F2-BDFE83C96D15}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>ChamChat</RootNamespace>
<AssemblyName>TSx</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Task.TSx.cs" />
<Compile Include="Client.TSx.cs" />
<Compile Include="Client.TSx.Specific.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Models\Models.csproj">
<Project>{09375A4A-28B8-427B-853D-75C03A070728}</Project>
<Name>Models</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("TSD100S")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Microsoft")]
[assembly: AssemblyProduct("TSD100S")]
[assembly: AssemblyCopyright("Copyright © Microsoft 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("2fc0fe7d-2c1d-4983-a44a-6c1fd33288e3")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -0,0 +1,657 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ChamChat.Models;
namespace ChamChat
{
public class TSx_Task : Task
{
// Each step is separately programmed to the TSE11.
// Steps are programmed at 110% of required step duration.
// End of program is always of shutdown type to avoid stressing to much. (Excluding last step)
// If next step is of different type (tA or tB), then the next temperature is prepared in other chamber.
// Default temperatures are 0 °C for tA and 85 °C for tB.
public TSx_Task(Client Client, Profile Profile)
: base(Client, Profile)
{
_Profile = Profile;
_Client = Client;
_SerSteps = _Profile.SerializedStepList;
// Limit tA is overall limit
_tAProfileLimit = 0;
foreach (Step s in _SerSteps)
if (s.LimitT < _tAProfileLimit)
_tAProfileLimit = s.LimitT;
// Limit tB is overall limit
_tBProfileLimit = 60;
foreach (Step s in _SerSteps)
if (s.LimitT > _tBProfileLimit)
_tBProfileLimit = s.LimitT;
}
private DateTime _dtIdlingStart = DateTime.Now.AddYears(10);
private const Int32 PollingIntervalSeconds = 10; // Interval in seconds for updating task progress
private const Int32 maxIdlingTimeSec = 60;
private List<Step> _SerSteps;
private double _tAProfileLimit = 0;
private double _tBProfileLimit = 0;
public override Boolean IsControlledProgrammable(Profile profile)
{
// Clear existing ClientMessages
_Client.ClientMessages = new List<ClientMessage>();
_NewProfileDuration = 0;
_ProfileNumOfSerialSteps = 1;
List<Profile> profiles = new List<Profile>();
int k = 0;
while (k < _SerSteps.Count)
{
Profile p = GetProfile(k);
profiles.Add(p);
k += _ProfileNumOfSerialSteps;
}
foreach (Profile p in profiles)
if (!_Client.IsProgrammable(p))
return false;
// If subsequent tA resp. tB steps differ more than 50 °C, overheat/overcool alarm will sound immediately.
// Limits can be set to 50 °C from temperature.
List<Step> tASteps = new List<Step>();
List<Step> tBSteps = new List<Step>();
// Create list of all tA steps resp. tB steps
foreach (Step s in _SerSteps)
if (s.T > 25)
tBSteps.Add(s);
else
tASteps.Add(s);
// Compare subsequent tA steps
for (int i = 1; i < tASteps.Count; i++)
{
double t1 = tASteps[i - 1].T;
double t2 = tASteps[i].T;
if (Math.Abs(t1 - t2) > 50)
{
string msg = string.Format("stepping from {0:0} to {1:0} will cause overcool alarm", t1, t2);
_Client.ClientMessages.Add(new ClientMessage("Program cannot be written to client: " + msg));
return false;
}
}
// Compare subsequent tB steps
for (int i = 1; i < tBSteps.Count; i++)
{
double t1 = tBSteps[i - 1].T;
double t2 = tBSteps[i].T;
if (Math.Abs(t1 - t2) > 50)
{
string msg = string.Format("stepping from {0:0} to {1:0} will cause overheat alarm", t1, t2);
_Client.ClientMessages.Add(new ClientMessage("Program cannot be written to client: " + msg));
return false;
}
}
return true;
}
protected override void ThreadStandAlone()
{
// Write profile
try
{
if (!_Client.WriteProfile(_Profile))
{
_Status = TaskStatus.Stopped;
return;
}
}
catch (Exception ex)
{
_Status = TaskStatus.ExceptionOccured;
_TaskProgress = string.Format("Client WriteProfile() exception: {0}", ex.Message);
return;
}
// Start client
try
{
if (!_Client.Start())
{
_Status = TaskStatus.Stopped;
return;
}
}
catch (Exception ex)
{
_Status = TaskStatus.ExceptionOccured;
_TaskProgress = string.Format("Client Start() exception: {0}", ex.Message);
return;
}
DateTime lastPolled = DateTime.Now;
while (_Status == TaskStatus.IsRunning)
{
// Poll only every 'PollingIntervalSeconds' seconds
if (DateTime.Now > lastPolled.AddSeconds(PollingIntervalSeconds))
{
// Is finished?
try
{
if (_Client.IsFinished())
{
_Status = TaskStatus.Finished;
continue;
}
}
catch { }
try
{
_TaskProgress = _Client.Progress();
}
catch { }
lastPolled = DateTime.Now;
}
System.Threading.Thread.Sleep(100);
if (_Status == TaskStatus.AbortRequested)
{
try
{
if (_Client.Stop())
_Status = TaskStatus.Aborted;
}
catch { }
}
_isKicking = true;
}
_isKicking = false;
}
private Double _NewProfileDuration = 0; // Duration of new profile in minutes
private int _ProfileNumOfSerialSteps = 1; // Number of steps from serial step list performed in new profile.
protected override void ThreadControlled()
{
Int32 iCurrentSerialStep = -1;
DateTime startOfCurrentProgram = new DateTime(1900, 1, 1);
DateTime endOfCurrentProgram = new DateTime(1900, 1, 1);
Step currentStep = _SerSteps[0];
DateTime lastPolled = DateTime.Now;
_NewProfileDuration = 0;
_ProfileNumOfSerialSteps = 1;
Profile newProfile;
while (_Status == TaskStatus.IsRunning || _Status == TaskStatus.NextStepRequested)
{
#warning Update 02/05/2016
// Proceed with next step if it is not the last one.
if (_Status == TaskStatus.NextStepRequested && iCurrentSerialStep < _SerSteps.Count - 1)
{
endOfCurrentProgram = DateTime.Now.AddYears(1);
_ProfileNumOfSerialSteps = 1;
}
if (DateTime.Now > endOfCurrentProgram)
{
iCurrentSerialStep += _ProfileNumOfSerialSteps; // Is starting step of newProfile to be executed
// Last step has been performed?
if (iCurrentSerialStep > _SerSteps.Count - 1)
{
_Client.Stop();
_Status = TaskStatus.Finished;
AddEventLog("Last step performed");
continue;
}
newProfile = new Profile();
try
{
//AddEventLog("Debugging: Getting profile for iCurrentSerialStep=" + iCurrentSerialStep.ToString());
newProfile = GetProfile(iCurrentSerialStep);
//AddEventLog("Debugging: Profile for iCurrentSerialStep: " + newProfile.ToString());
}
catch (Exception ex) { AddEventLog("GetProfile() error: " + ex.Message); }
RestartClient(newProfile); // RestartClient sets TaskStatus to IsRunning if succesfull.
if (_Status != TaskStatus.IsRunning)
continue;
// Update variables
startOfCurrentProgram = DateTime.Now;
endOfCurrentProgram = DateTime.Now.AddMinutes(_NewProfileDuration);
lastPolled = DateTime.Now;
// Update events
try
{
Step s1 = newProfile.Steps[0];
Step s2 = newProfile.Steps[1];
//AddEventLog("Profile in client: " + newProfile.ToString());
if (newProfile.Loops.Count == 1)
AddEventLog(string.Format("Set conditions: {0:0}h{1:00} @ {2:0} °C, {3:0}h{4:00} @ {5:0} °C, {6:0} cycles", s1.Hours, s1.Minutes, s1.T, s2.Hours, s2.Minutes, s2.T, newProfile.Loops[0].N));
else
AddEventLog(string.Format("Set conditions: {0:0}h{1:00} @ {2:0} °C, {3:0}h{4:00} @ {5:0} °C", s1.Hours, s1.Minutes, s1.T, s2.Hours, s2.Minutes, s2.T));
string s = string.Format("Partial profile end is {0:00}-{1:00} @ {2:00}:{3:00}:{4:00}", endOfCurrentProgram.Day, endOfCurrentProgram.Month, endOfCurrentProgram.Hour, endOfCurrentProgram.Minute, endOfCurrentProgram.Second);
AddEventLog(s);
}
catch (Exception ex) { AddEventLog("Update events: " + ex.Message); }
}
// Poll only every 'PollingIntervalSeconds' seconds
if (DateTime.Now > lastPolled.AddSeconds(PollingIntervalSeconds))
{
// Is finished?
try
{
if (_Client.IsFinished())
{
AddEventLog("Client finished, but task did not!");
if (_dtIdlingStart < DateTime.Now.AddSeconds(-maxIdlingTimeSec))
{
AddEventLog("Debugging: _dtIdlingStart < DateTime.Now.AddSeconds(-maxIdlingTimeSec)");
// _Status = TaskStatus.Interrupted; // Profile did not finish, client did
//continue;
}
else
{
_dtIdlingStart = DateTime.Now;
AddEventLog("Debugging: _dtIdlingStart set to "+_dtIdlingStart.ToString());
}
}
else
_dtIdlingStart = DateTime.Now.AddYears(10);
}
catch { _dtIdlingStart = DateTime.Now.AddYears(10); } // Always continue and keep trying
#region Taskprogress
try
{
double taskRunTime = (DateTime.Now - _startThread).TotalMinutes;
double pTest = Math.Min(100, Math.Floor(taskRunTime / _Profile.DurationMin * 100));
double taskTimeRemain = _Profile.DurationMin - taskRunTime;
double taskTimeRemainHrs = Math.Floor(taskTimeRemain / 60);
double taskTimeRemainMin = Math.Floor(taskTimeRemain - 60 * taskTimeRemainHrs);
double newProfileRuntime = (DateTime.Now - startOfCurrentProgram).TotalMinutes;
double pNewProfile = Math.Min(100, Math.Floor(newProfileRuntime / _NewProfileDuration * 100));
double profileTimeExecutedSoFar = newProfileRuntime;
for (int i = 0; i < iCurrentSerialStep; i++)
profileTimeExecutedSoFar += _SerSteps[i].DurationMin;
int serialStepNo = iCurrentSerialStep;
double min = 0;
for (int i = 0; i < _SerSteps.Count; i++)
{
min += _SerSteps[i].DurationMin;
if (min > profileTimeExecutedSoFar)
{
serialStepNo = i;
break;
}
}
_TaskProgress = String.Format("Step #{0:00}/{1:00} progress {2:0}%, test progress {3:0}%, remaining test time {4:0}h{5:00}m", serialStepNo + 1, _Profile.SerializedStepList.Count, pNewProfile, pTest, taskTimeRemainHrs, taskTimeRemainMin);
if (serialStepNo + 1 == _Profile.SerializedStepList.Count && pTest > 99.99)
_TaskProgress = "Profile executed";
}
catch { _TaskProgress = "n/a"; }
#endregion Taskprogress
lastPolled = DateTime.Now;
}
System.Threading.Thread.Sleep(200);
_isKicking = true;
}
if (_Status == TaskStatus.AbortRequested)
{
try
{
if (_Client.Stop())
_Status = TaskStatus.Aborted;
}
catch { }
}
_isKicking = false;
}
private void RestartClient(Profile newProfile)
{
// Stop client
try
{
AddEventLog("Info: Stopping client");
#warning Do not stop if this is the first parital profile
if (!_Client.Stop())
{
_Status = TaskStatus.Interrupted;
AddEventLog("Task interrupted while trying to stop client!");
return;
}
}
catch (Exception ex)
{
_Status = TaskStatus.ExceptionOccured;
_TaskProgress = string.Format("Client Stop() exception: {0}", ex.Message);
AddEventLog(_TaskProgress);
return;
}
// Wait to finish
try
{
Boolean timedOut = true;
DateTime startWait = DateTime.Now;
while (DateTime.Now < startWait.AddSeconds(60))
{
System.Threading.Thread.Sleep(1000);
if (_Client.IsFinished())
{
timedOut = false;
break;
}
}
if (timedOut)
{
_Status = TaskStatus.Interrupted;
AddEventLog("Time out (60 s) in RestartClient.WaitForFinish");
return;
}
}
catch (Exception ex)
{
_Status = TaskStatus.ExceptionOccured;
_TaskProgress = string.Format("Client WaitForFinish exception: {0}", ex.Message);
AddEventLog(_TaskProgress);
return;
}
AddEventLog("Info: Client stopped");
// Wait for move to end
try
{
if (!((TSx_Client)_Client).AwaitMoving(60))
{
_Status = TaskStatus.Interrupted;
AddEventLog("Time out (60 s) in RestartClient.AwaitMoving");
}
}
catch (Exception ex)
{
_Status = TaskStatus.ExceptionOccured;
_TaskProgress = string.Format("Client AwaitMoving() exception: {0}", ex.Message);
AddEventLog(_TaskProgress);
return;
}
// AddEventLog("Debugging: Client AwaitMoving done");
// Write profile
try
{
AddEventLog("Info: Writing to client");
if (!_Client.WriteProfile(newProfile))
{
_Status = TaskStatus.Interrupted;
AddEventLog("Task interrupted while trying to write new profile to client!");
return;
}
}
catch (Exception ex)
{
_Status = TaskStatus.ExceptionOccured;
_TaskProgress = string.Format("Client WriteProfile() exception: {0}", ex.Message);
AddEventLog(_TaskProgress);
return;
}
AddEventLog("Info: Profile written to client");
// Start client
try
{
AddEventLog("Info: Starting client");
if (!_Client.Start())
{
// Try to start again after 10 sec
AddEventLog("First attempt to start client failed!");
System.Threading.Thread.Sleep(10000);
if (!_Client.Start())
{
_Status = TaskStatus.Interrupted;
AddEventLog("Task interrupted while trying to start client!");
return;
}
}
}
catch (Exception ex)
{
_Status = TaskStatus.ExceptionOccured;
_TaskProgress = string.Format("Client Start() exception: {0}", ex.Message);
AddEventLog(_TaskProgress);
return;
}
AddEventLog("Info: Client started");
#warning Update 02/05/2016
_Status = TaskStatus.IsRunning;
}
private Profile GetProfile(int iStep)
{
Step nextStep = null;
if (iStep + 1 < _SerSteps.Count)
nextStep = _SerSteps[iStep + 1].DeepClone();
// Last tA set to client
double tALastSet = 0;
for (int i = 0; i < iStep; i++)
if (_SerSteps[i].T < 40)
tALastSet = _SerSteps[i].T;
double tAsetting = Math.Min(0, tALastSet + 40); // As high as possible without exceeding limits of prev step
// Last tB set to client
double tBLastSet = 0;
for (int i = 0; i < iStep; i++)
if (_SerSteps[i].T > 40)
tBLastSet = _SerSteps[i].T;
double tBsetting = Math.Max(60, tBLastSet - 40); // As low as possible without exceeding limits of prev step
// Create standard steps with 1 min duration
Step stdA = new Step(1);
stdA.T = tAsetting;
stdA.LimitT = tAsetting - 50; // Reset later
stdA.PreTemp = tAsetting;
Step stdB = new Step(1);
stdB.T = tBsetting;
stdB.LimitT = tBsetting + 50; // Reset later
stdB.PreTemp = tBsetting;
Step step1 = _SerSteps[iStep].DeepClone();
Step step2 = new Step(15);
// Programmed step is minimum 10 minutes, maxmimum 1.5 times the required step duration.
// If multiple steps can be performed without restart, the duration is altered below.
step1.DurationMin = Math.Max(10, Math.Round(1.5 * step1.DurationMin));
// Set time of restart to end of current step.
// If multiple steps can be performed without restart, the duration is altered below.
_NewProfileDuration = _SerSteps[iStep].DurationMin;
_ProfileNumOfSerialSteps = 1;
// Remark: Area to start in is defined by client based on step order.
if (step1.T > 40)
{
// Current step is tB, step 2 programmed to client must be tA
step2 = stdA;
if (nextStep != null)
if (nextStep.T < 40)
{
// If next step is tA, then program it as is.
step2 = nextStep.DeepClone();
//// The two steps can be run by client without restarting.
//// If no restarting takes place, then the next opposite step is not being prepared. The previous retains.
//step2.DurationMin = Math.Max(30, Math.Round(1.5 * step2.DurationMin));
//step1.DurationMin = _SerSteps[iStep].DurationMin;
//_NewProfileDuration = step1.DurationMin + step2.DurationMin;
//_ProfileNumOfSerialSteps = 2;
}
}
else
{
// Current step is tA, step 2 programmed to client must be tB
step2 = stdB;
if (nextStep != null)
if (nextStep.T > 40)
{
// If next step is tB, then program it as is.
step2 = nextStep.DeepClone();
//// The two steps can be run by client without restarting.
//// If no restarting takes place, then the next opposite step is not being prepared. The previous retains.
//step2.DurationMin = Math.Max(30, Math.Round(1.5 * step2.DurationMin));
//step1.DurationMin = _SerSteps[iStep].DurationMin;
//_NewProfileDuration = step1.DurationMin + step2.DurationMin;
//_ProfileNumOfSerialSteps = 2;
}
}
// Set PK
step1.PK = _SerSteps[iStep].PK; // Set for Loop.ToString()
step2.PK = _SerSteps[iStep].PK + 1;
// If current step is start of a loop comprising 2 opposite steps, then create loop in newProfile and set end time of newProfile
List<Loop> loops = new List<Loop>();
int N = 0;
foreach (Loop loop in _Profile.Loops)
{
if (loop.First == _SerSteps[iStep].PK && loop.Last == _SerSteps[iStep].PK + 1)
{
if ((step1.T < 40 && step2.T > 40) || (step1.T > 40 && step2.T < 40))
{
// Steps are in different chambers of client.
N = loop.N;
break;
}
}
}
if (N != 0)
{
loops.Add(new Loop(N, 0, 1)); // Loop is always from 1st to 2nd step
step1.DurationMin = _SerSteps[iStep].DurationMin;
step2.DurationMin = nextStep.DurationMin;
_NewProfileDuration = N * (step1.DurationMin + step2.DurationMin);
_ProfileNumOfSerialSteps = 2 * N;
}
// Set limits to max, but do not exceed profile limits
if (step1.T < 40)
{
step1.LimitT = Math.Max(step1.T - 50, _tAProfileLimit);
step2.LimitT = Math.Min(step2.T + 50, _tBProfileLimit);
}
else
{
step1.LimitT = Math.Min(step1.T + 50, _tBProfileLimit);
step2.LimitT = Math.Max(step2.T - 50, _tAProfileLimit);
}
List<Step> steps = new List<Step>();
steps.Add(step1);
steps.Add(step2);
List<ProfileOption> options = new List<ProfileOption>();
options.Add(ProfileOption.TSx_EndModeOff); // Shut down client
// NOTE: It is impossible to wait for setup, unless endofCurrentProgram is moved forwards.
options.Add(ProfileOption.TSx_StartNoSetup); // Do not wait for setup
//if (iStep == 0 && _Profile.Options.Contains(ProfileOption.TSE11A_StartSetupTest))
// options.Add(ProfileOption.TSE11A_StartSetupTest); // Wait for setup in first step
//else
// options.Add(ProfileOption.TSE11A_StartNoSetup); // Do not wait for setup
Profile newProfile = new Profile(_Profile.Title, steps, loops, options);
return newProfile;
}
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,4 @@
// <autogenerated />
using System;
using System.Reflection;
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.0", FrameworkDisplayName = ".NET Framework 4")]

View File

@@ -0,0 +1 @@
0d605b8d358746cb8dedaee3da21912cbaeec1bd

View File

@@ -0,0 +1,9 @@
\\silicium\software\MASER software\Source\ChamChat\Client_TSx\bin\Release\TSx.dll
\\silicium\software\MASER software\Source\ChamChat\Client_TSx\bin\Release\TSx.pdb
\\silicium\software\MASER software\Source\ChamChat\Client_TSx\bin\Release\ChamChat.Models.dll
\\silicium\software\MASER software\Source\ChamChat\Client_TSx\bin\Release\ChamChat.Models.pdb
\\silicium\software\MASER software\Source\ChamChat\Client_TSx\obj\Release\Client_TSx.csproj.AssemblyReference.cache
\\silicium\software\MASER software\Source\ChamChat\Client_TSx\obj\Release\Client_TSx.csproj.CoreCompileInputs.cache
\\silicium\software\MASER software\Source\ChamChat\Client_TSx\obj\Release\Client_TSx.csproj.CopyComplete
\\silicium\software\MASER software\Source\ChamChat\Client_TSx\obj\Release\TSx.dll
\\silicium\software\MASER software\Source\ChamChat\Client_TSx\obj\Release\TSx.pdb

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More