提交:初始化

This commit is contained in:
longfellowJian 2025-03-27 16:01:28 +08:00
commit 70fca2d84c
18 changed files with 1080 additions and 0 deletions

67
App.config Normal file
View File

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<!--<dependentAssembly>
<assemblyIdentity name="Tecan.At.Dragonfly.Framework" publicKeyToken="2ecf6b23f06e7950" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.3.0.0" newVersion="2.3.0.0" />
</dependentAssembly>-->
<!--<dependentAssembly>
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.4.1" newVersion="4.0.4.1" />
</dependentAssembly>-->
<!--<dependentAssembly>
<assemblyIdentity name="Tecan.At.Dragonfly.Data.DomainObjects.Workspace" publicKeyToken="2ecf6b23f06e7950" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.4.12.0" newVersion="2.4.12.0" />
</dependentAssembly>-->
<!--<dependentAssembly>
<assemblyIdentity name="Tecan.At.Dragonfly.Component.Shared" publicKeyToken="2ecf6b23f06e7950" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.3.0.0" newVersion="3.3.0.0" />
</dependentAssembly>-->
<!--<dependentAssembly>
<assemblyIdentity name="Tecan.At.Dragonfly.Imaging.Data" publicKeyToken="2ecf6b23f06e7950" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.4.3.0" newVersion="2.4.3.0" />
</dependentAssembly>-->
<!--<dependentAssembly>
<assemblyIdentity name="Tecan.At.Dragonfly.Component.Shared.Microplate" publicKeyToken="2ecf6b23f06e7950" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.2.0.0" newVersion="3.2.0.0" />
</dependentAssembly>-->
<!--<dependentAssembly>
<assemblyIdentity name="Tecan.At.Dragonfly.Imaging" publicKeyToken="2ecf6b23f06e7950" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.1.5.0" newVersion="3.1.5.0" />
</dependentAssembly>-->
</assemblyBinding>
</runtime>
</configuration>

View File

@ -0,0 +1,35 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.28307.1022
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SampleApp", "SampleApp.csproj", "{153C39DC-DB8A-4E8D-9503-A51F4BE96513}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{153C39DC-DB8A-4E8D-9503-A51F4BE96513}.Debug|x64.ActiveCfg = Debug|x64
{153C39DC-DB8A-4E8D-9503-A51F4BE96513}.Debug|x64.Build.0 = Debug|x64
{153C39DC-DB8A-4E8D-9503-A51F4BE96513}.Release|x64.ActiveCfg = Release|x64
{153C39DC-DB8A-4E8D-9503-A51F4BE96513}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E41B27F9-49B0-48B3-B3DD-9DA06108CE7B}
EndGlobalSection
GlobalSection(TeamFoundationVersionControl) = preSolution
SccNumberOfProjects = 1
SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C}
SccTeamFoundationServer = http://tfsapp01.tecan.net:8080/tfs/at_dragonfly
SccProjectUniqueName0 = SampleApp.csproj
SccProjectName0 = .
SccAuxPath0 = http://tfsapp01.tecan.net:8080/tfs/at_dragonfly
SccLocalPath0 = .
SccProvider0 = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,94 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Tecan.At.Dragonfly.AutomationInterface;
using Tecan.At.Dragonfly.AutomationInterface.Data;
using Tecan.At.Dragonfly.AutomationInterface.MethodModification;
namespace Tecan.At.AutomationInterface.SampleApp
{
public static class AutomationInterfaceAccess
{
public static IReadOnlyCollection<IInstrument> GetInstruments()
{
using (var ai = AutomationInterfaceFactory.Build())
{
return ai.InstrumentManagement.GetInstruments();
}
}
public static List<string> GetMethods()
{
using (var ai = AutomationInterfaceFactory.Build())
{
return ai.Queries.GetMethods().ToList();
}
}
public static string GetMethodXml(string methodName)
{
using (var ai = AutomationInterfaceFactory.Build())
{
return ai.Queries.GetMethodXml(methodName);
}
}
public static bool CheckMethod(IInstrument selectedInstrument, string methodAsXml, string methodName, out IEnumerable<string> messages)
{
messages = null;
using (var ai = AutomationInterfaceFactory.Build())
{
return ai.MethodExecution.CheckMethod(selectedInstrument, methodAsXml, methodName, out messages);
}
}
public static IMethodExecutionResult ExecuteMethod(IInstrument selectedInstrument, string methodAsXml, string methodName, bool isStacker)
{
using (var ai = AutomationInterfaceFactory.Build())
{
return ai.MethodExecution.ExecuteMethod(selectedInstrument, methodAsXml, methodName, isStacker);
}
}
public static Task<IMethodExecutionResult> ExecuteMethodAsync(IInstrument selectedInstrument, string methodAsXml, string methodName, bool isStacker)
{
using (var ai = AutomationInterfaceFactory.Build())
{
return ai.MethodExecution.ExecuteMethodAsync(selectedInstrument, methodAsXml, methodName, isStacker);
}
}
public static void CancelAsyncMethodExecution(IInstrument selectedInstrument)
{
using (var ai = AutomationInterfaceFactory.Build())
{
ai.MethodExecution.Cancel(selectedInstrument);
}
}
public static string ExportData(Guid workspaceId, Guid executionId)
{
using (var ai = AutomationInterfaceFactory.Build())
{
return ai.MethodExecution.GetResults(workspaceId, executionId);
}
}
public static string ChangePlateLayout(string methodAsXml, int[] wellsToSelect)
{
using (var plateLayoutModifier = MethodModificationFactory.Build<IModifyPlateLayout>(ref methodAsXml))
{
var plateInfo = plateLayoutModifier.GetPlateInfo();
for (uint wellIndex = 0; wellIndex < plateInfo.WellAmount; wellIndex++)
{
plateLayoutModifier.SelectWell(wellIndex, wellsToSelect.Any(x => x == wellIndex));
}
methodAsXml = plateLayoutModifier.ApplyChangesToXmlString();
}
return methodAsXml;
}
}
}

63
CreateZipFile.ps1 Normal file
View File

@ -0,0 +1,63 @@
try
{
# see https://stackoverflow.com/questions/9948517/how-to-stop-a-powershell-script-on-the-first-error
$ErrorActionPreference = "Stop"
Add-Type -A System.IO.Compression.FileSystem
# Write-Host ('OS Tmp Dir: ' + $env:TEMP )
# create tmo dir
$tmpDir = $env:TEMP + [guid]::NewGuid()
Write-Host ('Use tmp-dir: ' + $tmpDir)
New-Item -ItemType Directory -Force -Path $tmpDir
# copy Sample App source code files to tmp dir
Copy-Item $($PSScriptRoot + "\*.cs") -Destination $tmpDir
Copy-Item $($PSScriptRoot + "\*.config") -Destination $tmpDir
Copy-Item $($PSScriptRoot + "\*.csproj") -Destination $tmpDir
Copy-Item $($PSScriptRoot + "\*.sln") -Destination $tmpDir
Copy-Item $($PSScriptRoot + "\*.txt") -Destination $tmpDir
Copy-Item $($PSScriptRoot + "\Properties") -Destination $tmpDir -Recurse
# copy Automation Interface docu to tmp dir
# -> PDF is currently not included into ZIP file
# $aiDocuFileName = Resolve-Path -Path $($PSScriptRoot + "\..\..\Production\Automation\AutomationInterface\Doc\AutomationInterfaceManual.pdf")
# Write-Host ('aiDocuFileName : ' + $aiDocuFileName )
# Copy-Item $aiDocuFileName -Destination $tmpDir
# create zip file
$zipFileName = $PSScriptRoot + "\SampleApp.zip"
Write-Host ('zipFileName: ' + $zipFileName )
if (Test-Path $zipFileName)
{
Write-Host("Delete already available .zip file...")
Remove-Item -Recurse -Force $zipFileName
}
# ...and create it
[IO.Compression.ZipFile]::CreateFromDirectory($tmpDir, $zipFileName)
# delete temp directory
Write-Host ('Del tmp folder : ' + $tmpDir )
Remove-Item -Recurse -Force $tmpDir
Write-Host('')
Write-Host('')
Write-Host('##############################################################################')
Write-Host('Successfully created Sample Application .zip file: ' + $zipFileName)
Write-Host('##############################################################################')
exit $LASTEXITCODE
}
catch
{
Write-Error('ERROR: ' + $_.Exception)
exit $LASTEXITCODE
}

17
DemoAttribute.cs Normal file
View File

@ -0,0 +1,17 @@
using System;
namespace Tecan.At.AutomationInterface.SampleApp
{
[AttributeUsage(AttributeTargets.Method)]
public class DemoAttribute : Attribute
{
public string Name { get; private set; }
public char Key { get; private set; }
public DemoAttribute(string name, char key)
{
Name = name;
Key = key;
}
}
}

11
ExportDemo.cs Normal file
View File

@ -0,0 +1,11 @@
namespace Tecan.At.AutomationInterface.SampleApp
{
internal class ExportDemo
{
[Demo("exportData", 'a')]
public static void Export(SampleApp sampleApp, SessionData sessionData)
{
sampleApp.ExportData(sessionData);
}
}
}

92
InputData.cs Normal file
View File

@ -0,0 +1,92 @@
using System;
using System.Collections.Generic;
namespace Tecan.At.AutomationInterface.SampleApp
{
public enum AutomationInterfaceActions
{
Undefined,
GetInstrument,
GetAllMethods,
GetMethod,
CheckMethod,
ExecuteMethod,
PlateOut,
PlateIn,
ExportData,
ClearSession,
StartWorkflow
}
public class InputData
{
public AutomationInterfaceActions Action { get; private set; }
public List<string> Parameter { get; } = new List<string>();
public bool Parse(string value)
{
if (string.IsNullOrWhiteSpace(value))
return false;
string[] parts = value.Split(new[] {" "}, StringSplitOptions.RemoveEmptyEntries);
if (!GetAction(parts[0]))
{
return false;
}
for (int i = 1; i < parts.Length; i++)
{
Parameter.Add(parts[i]);
}
return true;
}
private bool GetAction(string part)
{
if (!part.StartsWith("-"))
{
return false;
}
switch (part.ToLower())
{
case "-getinstrument":
Action = AutomationInterfaceActions.GetInstrument;
break;
case "-getallmethods":
Action = AutomationInterfaceActions.GetAllMethods;
break;
case "-getmethod":
Action = AutomationInterfaceActions.GetMethod;
break;
case "-checkmethod":
Action = AutomationInterfaceActions.CheckMethod;
break;
case "-executemethod":
Action = AutomationInterfaceActions.ExecuteMethod;
break;
case "-plateout":
Action = AutomationInterfaceActions.PlateOut;
break;
case "-platein":
Action = AutomationInterfaceActions.PlateIn;
break;
case "-exportdata":
Action = AutomationInterfaceActions.ExportData;
break;
case "-clearsession":
Action = AutomationInterfaceActions.ClearSession;
break;
case "-startworkflow":
Action = AutomationInterfaceActions.StartWorkflow;
break;
default:
return false;
}
return true;
}
}
}

60
InstrumentDemo.cs Normal file
View File

@ -0,0 +1,60 @@
using System;
using Tecan.At.Dragonfly.AutomationInterface;
namespace Tecan.At.AutomationInterface.SampleApp
{
internal class InstrumentDemo
{
[Demo("getInstrument <alias>", '1')]
public static void GetInstrumentByAlias(SampleApp sampleApp, SessionData sessionData)
{
Console.Write("Instrument alias? ");
var aliasPart = Console.ReadLine();
sampleApp.GetInstrument(sessionData, aliasPart);
if (sessionData?.SelectedInstrument != null)
{
Console.WriteLine($"Selected instrument: {sessionData.SelectedInstrument.Alias ?? "<N.A.>"}");
}
else
{
Console.WriteLine($"No instrument available");
}
}
[Demo("plateOut", '8')]
public static void PlateOut(SampleApp sampleApp, SessionData sessionData)
{
sessionData.EnforceSetInstrument();
using (AutomationInterfaceFactory.Build())
{
sessionData.SelectedInstrument.PlateOut();
}
}
[Demo("plateIn", '9')]
public static void PlateIn(SampleApp sampleApp, SessionData sessionData)
{
sessionData.EnforceSetInstrument();
using (AutomationInterfaceFactory.Build())
{
sessionData.SelectedInstrument.PlateIn();
}
}
[Demo("getInstrumentState", 'f')]
public static void GetState(SampleApp sampleApp, SessionData sessionData)
{
sessionData.EnforceSetInstrument();
using (AutomationInterfaceFactory.Build())
{
Console.WriteLine($"Instrument state is '{ sessionData.SelectedInstrument.State}'.");
}
}
}
}

61
MethodExecutionDemo.cs Normal file
View File

@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
namespace Tecan.At.AutomationInterface.SampleApp
{
internal class MethodExecutionDemo
{
[Demo("checkMethod <methodFile>", '4')]
public static void CheckMethod(SampleApp sampleApp, SessionData sessionData)
{
Console.Write("methodFile? ");
var methodFile = Console.ReadLine();
IEnumerable<string> messages;
sampleApp.CheckMethod(sessionData, methodFile, out messages);
Console.WriteLine(sessionData.MethodIsValid ? "valid" : "invalid");
foreach (var message in messages)
{
Console.WriteLine(message);
}
}
[Demo("executeMethod <methodFile>", '5')]
public static void ExecuteMethod(SampleApp sampleApp, SessionData sessionData)
{
Console.Write("methodFile? ");
var methodFile = Console.ReadLine();
sampleApp.ExecuteMethod(sessionData, methodFile, "AutomationInterfaceMethod", new int[] { });
}
[Demo("executeMethodAsync <methodFile>", '6')]
public static void ExecuteMethodAsync(SampleApp sampleApp, SessionData sessionData)
{
Console.Write("methodFile? ");
var methodFile = Console.ReadLine();
sampleApp.ExecuteMethodAsync(sessionData, methodFile, "AutomationInterfaceMethod", new int[] { });
}
[Demo("executeMethodAsyncAndCancel <methodFile>", '7')]
public static void ExecuteMethodAsyncWithCancellation(SampleApp sampleApp, SessionData sessionData)
{
Console.Write("methodFile? ");
var methodFile = Console.ReadLine();
sampleApp.ExecuteMethodAsyncAndCancel(sessionData, methodFile, "AutomationInterfaceMethod", new int[] { });
}
[Demo("executeMethod (with stacker) <methodFile>", 'e')]
public static void ExecuteMethodWithStacker(SampleApp sampleApp, SessionData sessionData)
{
Console.Write("methodFile? ");
var methodFile = Console.ReadLine();
sampleApp.ExecuteMethod(sessionData, methodFile, "AutomationInterfaceMethod", new int[] { }, true);
}
}
}

15
MiscDemo.cs Normal file
View File

@ -0,0 +1,15 @@
namespace Tecan.At.AutomationInterface.SampleApp
{
internal class MiscDemo
{
[Demo("No Automation Interface scope available", 'd')]
public static void Export(SampleApp sampleApp, SessionData sessionData)
{
// inside method a scope is spanned
sampleApp.GetInstrument(sessionData, string.Empty);
// no scope here
sessionData.SelectedInstrument.PlateIn();
}
}
}

119
Program.cs Normal file
View File

@ -0,0 +1,119 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Tecan.At.Dragonfly.AutomationInterface;
namespace Tecan.At.AutomationInterface.SampleApp
{
class Program
{
static void Main(string[] args)
{
var commands = BuildCommands();
try
{
// Needed in your code
AutomationInterfaceFactory.Start();
SessionData sessionData = null;
var automationInterfaceAccess = new SampleApp();
var quitCommands = new[] { "q", "Q" };
while (true)
{
RenderMenu(commands);
var consoleInput = Console.ReadKey();
Console.WriteLine();
if (quitCommands.Any(x => x == consoleInput.KeyChar.ToString()))
{
break;
}
var command = '0';
if (!char.TryParse(consoleInput.KeyChar.ToString(), out command))
{
Console.WriteLine($"'{consoleInput}' isn't a valid command key.");
continue;
}
else if (commands.ContainsKey(command))
{
if (sessionData == null)
{
sessionData = new SessionData();
}
try
{
var theCommand = commands[command];
Console.WriteLine($"--- Execute command {theCommand.Item1}...");
theCommand.Item2.Invoke(automationInterfaceAccess, sessionData);
Console.WriteLine("--- done");
}
catch (TargetInvocationException e)
{
Console.WriteLine($"### Error: {e.InnerException.Message} ###");
Console.WriteLine();
Console.WriteLine(e.InnerException.ToString());
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
else
{
Console.WriteLine($"Unknown command '{command}'.");
}
}
}
finally
{
// Needed in your code
AutomationInterfaceFactory.Stop();
}
}
private static void RenderMenu(Dictionary<char, Tuple<string, Action<SampleApp, SessionData>>> commands)
{
Console.WriteLine();
commands.Keys.OrderBy(x => x).ToList().ForEach(c =>
{
var actCmd = commands[c];
Console.WriteLine($"{c}. {actCmd.Item1}");
});
Console.WriteLine();
Console.WriteLine($"Press q to exit.");
Console.WriteLine();
Console.Write("> ");
}
private static Dictionary<char, Tuple<string, Action<SampleApp, SessionData>>> BuildCommands()
{
var methods = typeof(Program).Assembly.GetTypes()
.SelectMany(t => t.GetMethods())
.Where(m => m.GetCustomAttributes(typeof(DemoAttribute), false).Length > 0)
.Select(x => new { Attribute = (DemoAttribute)x.GetCustomAttributes(typeof(DemoAttribute), false).Single(), Delegate = x })
.ToArray();
var commands = new Dictionary<char, Tuple<string, Action<SampleApp, SessionData>>>(methods.Length);
foreach (var actDemo in methods)
{
commands.Add(actDemo.Attribute.Key, Tuple.Create<string, Action<SampleApp, SessionData>>(actDemo.Attribute.Name, (aia, sd) => { actDemo.Delegate.Invoke(null, new object[] { aia, sd }); }));
}
Console.WriteLine($"Count: " + methods.Length);
return commands;
}
}
}

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("AutomationInterface.IntegrationsTestsConsole")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("AutomationInterface.IntegrationsTestsConsole")]
[assembly: AssemblyCopyright("Copyright © 2019")]
[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("153c39dc-db8a-4e8d-9503-a51f4be96513")]
// 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")]

41
QueryDemo.cs Normal file
View File

@ -0,0 +1,41 @@
using System;
namespace Tecan.At.AutomationInterface.SampleApp
{
internal class QueryDemo
{
[Demo("getMethods", '2')]
public static void GetAllMethods(SampleApp sampleApp, SessionData sessionData)
{
sampleApp.GetMethods(sessionData);
foreach (var methodName in sessionData.AvailableMethods)
{
Console.WriteLine(methodName);
}
}
[Demo("getMethodXml<methodName> <targetFileName>", '3')]
public static void GetMethodByNameAndTarget(SampleApp sampleApp, SessionData sessionData)
{
Console.Write("method name? ");
var methodName = Console.ReadLine();
var xmlString = sampleApp.GetMethodXml(methodName);
if (String.IsNullOrWhiteSpace(xmlString))
{
Console.WriteLine($"Method '{methodName}' not available.");
return;
}
Console.WriteLine($"Loaded method '{methodName}'. Length: '{xmlString.Length}'.");
Console.Write("target file name? ");
var targetFileName = Console.ReadLine();
// Console.WriteLine(xmlString);
System.IO.File.WriteAllText(targetFileName, xmlString);
}
}
}

21
README.txt Normal file
View File

@ -0,0 +1,21 @@
Automation Interface Sample Application
-----------------------------------------
To get the Sample Application running follow these steps:
1. Add a reference to your project to the file 'Tecan.At.Dragonfly.AutomationInterface.dll'.
This file is located in the Clients folder usually under C:\Program Files\Tecan\SparkControl.
2. In Visual Studio project post build event add call to a powershell script.
The script is called 'CopyAdditionalAutomationInterfaceFiles.ps1' and is located in the same folder as the 'AutomationInterface.dll'.
Example:
powershell.exe <your path>\CopyAdditionalAutomationInterfaceFiles.ps1 $(TargetDir)
Remark:
It might be necessary that you add following call in your pre-build step:
powershell.exe Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Unrestricted -Force;
Try it first without this call!

185
SampleApp.cs Normal file
View File

@ -0,0 +1,185 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Tecan.At.AutomationInterface.SampleApp
{
public class SampleApp
{
public void GetInstrument(SessionData sessionData, string aliasPart)
{
try
{
var availableInstruments = AutomationInterfaceAccess.GetInstruments();
sessionData.SelectedInstrument = availableInstruments.FirstOrDefault(x => string.IsNullOrEmpty(aliasPart) || x.Alias.Contains(aliasPart));
if (sessionData.SelectedInstrument == null)
{
sessionData.SelectedInstrument = availableInstruments.FirstOrDefault(x => string.IsNullOrEmpty(aliasPart) || x.SerialNumber.Contains(aliasPart));
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
public void GetMethods(SessionData sessionData)
{
try
{
sessionData.AvailableMethods = AutomationInterfaceAccess.GetMethods();
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
public string GetMethodXml(string methodName)
{
try
{
return AutomationInterfaceAccess.GetMethodXml(methodName);
}
catch (Exception e)
{
Console.WriteLine(e);
return null;
}
}
public void CheckMethod(SessionData sessionData, string methodFile, out IEnumerable<string> messages)
{
sessionData.EnforceSetInstrument();
messages = null;
try
{
string methodAsXml = System.IO.File.ReadAllText(methodFile);
sessionData.MethodIsValid = AutomationInterfaceAccess.CheckMethod(sessionData.SelectedInstrument, methodAsXml, "MethodToCheck", out messages);
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
public void ExecuteMethod(SessionData sessionData, string methodFile, string methodName, int[] wellsToSelect, bool isStacker = false)
{
sessionData.EnforceSetInstrument();
try
{
string methodAsXml = System.IO.File.ReadAllText(methodFile);
if (wellsToSelect.Any())
{
methodAsXml = AutomationInterfaceAccess.ChangePlateLayout(methodAsXml, wellsToSelect);
}
var result = AutomationInterfaceAccess.ExecuteMethod(sessionData.SelectedInstrument, methodAsXml, methodName, isStacker);
if (result != null)
{
sessionData.WorkspaceId = result.WorkspaceId;
sessionData.ExecutionId = result.ExecutionId;
}
else
{
Console.WriteLine("Error executing method (checkMethod failed).");
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
public void ExecuteMethodAsync(SessionData sessionData, string methodFile, string methodName, int[] wellsToSelect, bool isStacker = false)
{
sessionData.EnforceSetInstrument();
try
{
string methodAsXml = System.IO.File.ReadAllText(methodFile);
if (wellsToSelect.Any())
{
methodAsXml = AutomationInterfaceAccess.ChangePlateLayout(methodAsXml, wellsToSelect);
}
var task = AutomationInterfaceAccess.ExecuteMethodAsync(sessionData.SelectedInstrument, methodAsXml, methodName, isStacker);
Console.WriteLine($"Started method '{methodName}'...");
while (task.Status == TaskStatus.Running)
{
Thread.Sleep(1000);
Console.Write(".");
}
task.Wait();
if (task.Result != null)
{
sessionData.WorkspaceId = task.Result.WorkspaceId;
sessionData.ExecutionId = task.Result.ExecutionId;
Console.WriteLine();
Console.WriteLine($"Executed method '{methodName}'. WorkspaceId: '{sessionData.WorkspaceId}'.");
}
else
{
Console.WriteLine("Error executing method (checkMethod failed).");
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
public void ExecuteMethodAsyncAndCancel(SessionData sessionData, string methodFile, string methodName, int[] wellsToSelect, bool isStacker = false)
{
sessionData.EnforceSetInstrument();
try
{
string methodAsXml = System.IO.File.ReadAllText(methodFile);
if (wellsToSelect.Any())
{
methodAsXml = AutomationInterfaceAccess.ChangePlateLayout(methodAsXml, wellsToSelect);
}
var task = AutomationInterfaceAccess.ExecuteMethodAsync(sessionData.SelectedInstrument, methodAsXml, methodName, isStacker);
Console.WriteLine($"Started method '{methodName}'...");
// method should be a rather complex method that it takes longer to execute as this thread is sleeping
Thread.Sleep(5000);
Console.WriteLine($"Cancel method execution.");
AutomationInterfaceAccess.CancelAsyncMethodExecution(sessionData.SelectedInstrument);
Console.WriteLine($"Cancellation finished.");
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
public void ExportData(SessionData sessionData)
{
try
{
sessionData.ExportedDataFile = AutomationInterfaceAccess.ExportData(sessionData.WorkspaceId, sessionData.ExecutionId);
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
}
}

78
SampleApp.csproj Normal file
View File

@ -0,0 +1,78 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{153C39DC-DB8A-4E8D-9503-A51F4BE96513}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>Tecan.At.AutomationInterface.SampleApp</RootNamespace>
<AssemblyName>Tecan.At.AutomationInterface.SampleApp</AssemblyName>
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
<SccProjectName>SAK</SccProjectName>
<SccLocalPath>SAK</SccLocalPath>
<SccAuxPath>SAK</SccAuxPath>
<SccProvider>SAK</SccProvider>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.ServiceProcess" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Xml" />
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<Compile Include="DemoAttribute.cs" />
<Compile Include="ExportDemo.cs" />
<Compile Include="InstrumentDemo.cs" />
<Compile Include="MethodExecutionDemo.cs" />
<Compile Include="MiscDemo.cs" />
<Compile Include="QueryDemo.cs" />
<Compile Include="SampleApp.cs" />
<Compile Include="InputData.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SessionData.cs" />
<Compile Include="AutomationInterfaceAccess.cs" />
<Compile Include="WorkflowDemo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<Content Include="README.txt" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PreBuildEvent>powershell.exe Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Unrestricted -Force;</PreBuildEvent>
</PropertyGroup>
<PropertyGroup>
<PostBuildEvent>powershell.exe &lt;your path&gt;\CopyAdditionalAutomationInterfaceFiles.ps1 $(TargetDir)</PostBuildEvent>
</PropertyGroup>
</Project>

24
SessionData.cs Normal file
View File

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using Tecan.At.Dragonfly.AutomationInterface.Data;
namespace Tecan.At.AutomationInterface.SampleApp
{
public class SessionData
{
public List<string> AvailableMethods { get; set; }
public IInstrument SelectedInstrument { get; set; }
public bool MethodIsValid { get; set; }
public Guid WorkspaceId { get; set; }
public Guid ExecutionId { get; set; }
public string ExportedDataFile { get; set; }
public void EnforceSetInstrument()
{
if (SelectedInstrument == null)
{
throw new InvalidOperationException("Instrument is not set.");
}
}
}
}

61
WorkflowDemo.cs Normal file
View File

@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
namespace Tecan.At.AutomationInterface.SampleApp
{
internal class WorkflowDemo
{
[Demo("startWorkflow <methodFile>", 'b')]
public static void Export(SampleApp sampleApp, SessionData sessionData)
{
Console.Write("instrument alias? ");
var instrumentAlias = Console.ReadLine();
Console.WriteLine("methodFile? ");
var methodFile = Console.ReadLine();
sessionData = new SessionData();
sampleApp.GetInstrument(sessionData, instrumentAlias);
sampleApp.ExecuteMethod(sessionData, methodFile, "AutomationInterfaceMethod", new int[] { });
sampleApp.ExportData(sessionData);
Console.WriteLine("Export: " + sessionData.ExportedDataFile);
}
[Demo("select wells and execute <instrumentAlias> <methodFile> <wellIndices>", 'c')]
public static void SelectWellsAndExport(SampleApp sampleApp, SessionData sessionData)
{
Console.Write("instrument alias? ");
var instrumentAlias = Console.ReadLine();
Console.WriteLine("methodFile? ");
var methodFile = Console.ReadLine();
Console.WriteLine("wells to select? Bsp: 2, 5, 32, ...");
var wellsToSelectString = Console.ReadLine();
List<int> wellsToSelect = new List<int>();
if (!string.IsNullOrWhiteSpace(wellsToSelectString))
{
string[] intParts = wellsToSelectString.Split(new char[] { ',' });
foreach (var intPart in intParts)
{
if (int.TryParse(intPart.Trim(), out int wellIndex))
{
wellsToSelect.Add(wellIndex);
}
}
}
sessionData = new SessionData();
sampleApp.GetInstrument(sessionData, instrumentAlias);
sampleApp.ExecuteMethod(sessionData, methodFile, "AutomationInterfaceMethod", wellsToSelect.ToArray());
sampleApp.ExportData(sessionData);
Console.WriteLine("Export: " + sessionData.ExportedDataFile);
}
}
}