diff --git a/C#/XA/UMCx/App.config b/C#/XA/UMCx/App.config
new file mode 100644
index 0000000..56efbc7
--- /dev/null
+++ b/C#/XA/UMCx/App.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/C#/XA/UMCx/Program.cs b/C#/XA/UMCx/Program.cs
new file mode 100644
index 0000000..a0e457c
--- /dev/null
+++ b/C#/XA/UMCx/Program.cs
@@ -0,0 +1,159 @@
+// Title: UMCX
+// Created Date: 23/06/2026
+// Last Modified Date: 23/06/2026
+// .NET Framework version: 4.7.2
+// Thorlabs DLL version: 1.6.8.27431
+// Example Description:
+// This example demonstrates how to set-up the communication for the Thorlabs
+// UMCX controllers with a brushless stage, home it, and move it by 1 mm or degrees.
+
+using System;
+using System.Threading;
+using Thorlabs.MotionControl.XA;
+using Thorlabs.MotionControl.XA.Products;
+
+namespace UMC.net_testing
+{
+ class Program
+ {
+ //Change this line to match the serial number on your device (format: 121XXXXXX)
+ private static string _deviceId = "121000020";
+ //Select the channel to control ("1", "2", or "3")
+ private static string _channelNumber = "1";
+
+ static void Main(string[] args)
+ {
+ SystemManager systemManager;
+
+ //Start up XA
+ try
+ {
+ systemManager = SystemManager.Create();
+ systemManager.Startup();
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine("Exception: {0}", ex.Message);
+ return;
+ }
+
+
+ //Get the device list
+ System.Collections.Generic.IList devicelist = systemManager.GetDeviceList();
+
+ // Print all connected devices
+ Console.WriteLine("Connected devices: {0}", devicelist?.Count ?? 0);
+ if (devicelist != null && devicelist.Count > 0)
+ {
+ int index = 1;
+
+ foreach (var d in devicelist)
+ {
+ Console.Write("Device {0}: ", index);
+ try
+ {
+ Console.WriteLine("{0}, Serial Number: {1}", d.DeviceType, d.Device);
+
+ }
+ catch
+ {
+ Console.WriteLine(d?.ToString() ?? "");
+ }
+
+ index++;
+ }
+ }
+ else
+ {
+ Console.WriteLine("No devices found.");
+ }
+
+ //Open the UMCx device
+ Umcx device;
+ bool ret = systemManager.TryOpenDevice(_deviceId, "", OperatingModes.Default, out device);
+ if (ret == false)
+ {
+ Console.WriteLine("\nFail to open base unit {0}", _deviceId);
+ systemManager.Shutdown();
+ return;
+ }
+ else
+ {
+ Console.WriteLine("\nBase Unit {0} opened successfully", _deviceId);
+ }
+
+ //Open the channel
+ UmcxBrushlessLogicalChannel channel; //Make sure to choose the correct stage type for the channel, i.e. UmcxBrushlessLogicalChannel or UmcxStepperLogicalChannel
+ string _channelId = _deviceId + "-" + _channelNumber;
+ ret = systemManager.TryOpenDevice(_channelId, "", OperatingModes.Default, out channel);
+ if (ret == false)
+ {
+ Console.WriteLine("Fail to open channel {0}", channel.DeviceId);
+ systemManager.Shutdown();
+ return;
+ }
+ else
+ {
+ Console.WriteLine("Channel {0} opened successfully", channel.DeviceId);
+ }
+
+ try
+ {
+ //Enable the device
+ channel.SetEnableState(EnableState.Enabled, TimeSpan.FromSeconds(1));
+
+ //Get the stage information
+ ConnectedProductInfo connectedProductInfo = channel.GetConnectedProductInfo();
+ Console.WriteLine("Channel {0} Stage Name:{1}", channel.DeviceId, connectedProductInfo.ProductName);
+
+ //Home the device
+ Console.WriteLine("Homing");
+ channel.Home(TimeSpan.FromSeconds(60));
+ Console.WriteLine("Home completed");
+
+ //Set the distance. Unit: millimeters or degrees depending on the actuator
+ double distance = 1;
+
+ //Get the unit type of the actuator
+ Unit deviceUnit = connectedProductInfo.UnitType;
+
+ //Convert the distance to device unit
+ long posInDeviceUnits = channel.FromPhysicalToDeviceUnit(ScaleType.Distance, deviceUnit, distance);
+ Thread.Sleep(500);
+
+ //Move the device
+ Console.WriteLine("Moving to {0} {1}", distance, deviceUnit.ToString());
+ channel.Move(MoveMode.Absolute, (int)posInDeviceUnits, TimeSpan.FromSeconds(60));
+ Console.WriteLine("Move completed");
+
+ //Get the current position
+ int currentPosInDeviceUnits = channel.GetPositionCounter(TimeSpan.FromSeconds(1));
+
+ //Convert the device unit to physical unit
+ UnitConversionResult currentPos = channel.FromDeviceUnitToPhysical(ScaleType.Distance, currentPosInDeviceUnits);
+ Console.WriteLine("Current Position: {0} {1}", currentPos.Value, currentPos.UnitType);
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine("Exception: {0}", ex.Message);
+ }
+ finally
+ {
+ //Close the channel
+ if (channel != null)
+ channel.Close();
+
+ //Close the device
+ if (device != null)
+ {
+ device.Disconnect();
+ device.Close();
+ }
+
+ //Shutdown XA
+ systemManager.Shutdown();
+
+ }
+ }
+ }
+}
diff --git a/C#/XA/UMCx/Properties/AssemblyInfo.cs b/C#/XA/UMCx/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..0b43bcd
--- /dev/null
+++ b/C#/XA/UMCx/Properties/AssemblyInfo.cs
@@ -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("UMC .net testing")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("UMC .net testing")]
+[assembly: AssemblyCopyright("Copyright © 2026")]
+[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("12c10132-4d7d-4940-a749-b41cee252bb6")]
+
+// 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")]
diff --git a/C#/XA/UMCx/UMCx.csproj b/C#/XA/UMCx/UMCx.csproj
new file mode 100644
index 0000000..49ffe10
--- /dev/null
+++ b/C#/XA/UMCx/UMCx.csproj
@@ -0,0 +1,77 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {12C10132-4D7D-4940-A749-B41CEE252BB6}
+ Exe
+ UMC.net_testing
+ UMC.net_testing
+ v4.7.2
+ 512
+ true
+ true
+
+
+ AnyCPU
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ AnyCPU
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+ true
+ bin\x64\Debug\
+ DEBUG;TRACE
+ full
+ x64
+ 7.3
+ prompt
+ true
+
+
+ bin\x64\Release\
+ TRACE
+ true
+ pdbonly
+ x64
+ 7.3
+ prompt
+ true
+
+
+
+
+
+
+
+
+
+
+
+ False
+ bin\Debug\tlmc_xa_dotnet.dll
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/C#/XA/UMCx/obj/Debug/.NETFramework,Version=v4.7.2.AssemblyAttributes.cs b/C#/XA/UMCx/obj/Debug/.NETFramework,Version=v4.7.2.AssemblyAttributes.cs
new file mode 100644
index 0000000..3871b18
--- /dev/null
+++ b/C#/XA/UMCx/obj/Debug/.NETFramework,Version=v4.7.2.AssemblyAttributes.cs
@@ -0,0 +1,4 @@
+//
+using System;
+using System.Reflection;
+[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
diff --git a/C#/XA/UMCx/obj/Debug/UMCx.csproj.FileListAbsolute.txt b/C#/XA/UMCx/obj/Debug/UMCx.csproj.FileListAbsolute.txt
new file mode 100644
index 0000000..9f799f8
--- /dev/null
+++ b/C#/XA/UMCx/obj/Debug/UMCx.csproj.FileListAbsolute.txt
@@ -0,0 +1,9 @@
+C:\Users\cstroud\source\repos\UMC .net testing\obj\x64\Debug\UMC .net testing.csproj.AssemblyReference.cache
+C:\Users\cstroud\source\repos\UMC .net testing\obj\x64\Debug\UMC .net testing.csproj.CoreCompileInputs.cache
+C:\Users\cstroud\source\repos\UMC .net testing\bin\x64\Debug\UMC.net_testing.exe.config
+C:\Users\cstroud\source\repos\UMC .net testing\bin\x64\Debug\UMC.net_testing.exe
+C:\Users\cstroud\source\repos\UMC .net testing\bin\x64\Debug\UMC.net_testing.pdb
+C:\Users\cstroud\source\repos\UMC .net testing\bin\x64\Debug\tlmc_xa_dotnet.dll
+C:\Users\cstroud\source\repos\UMC .net testing\obj\x64\Debug\UMC .net testing.csproj.CopyComplete
+C:\Users\cstroud\source\repos\UMC .net testing\obj\x64\Debug\UMC.net_testing.exe
+C:\Users\cstroud\source\repos\UMC .net testing\obj\x64\Debug\UMC.net_testing.pdb
diff --git a/C#/XA/UMCx/obj/Debug/UMCx.exe.config b/C#/XA/UMCx/obj/Debug/UMCx.exe.config
new file mode 100644
index 0000000..56efbc7
--- /dev/null
+++ b/C#/XA/UMCx/obj/Debug/UMCx.exe.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/C++/XA/UMCx/UMCx.cpp b/C++/XA/UMCx/UMCx.cpp
new file mode 100644
index 0000000..8060d9c
--- /dev/null
+++ b/C++/XA/UMCx/UMCx.cpp
@@ -0,0 +1,141 @@
+/*
+Title: UMCx
+Created date: 24/06/2026
+Last Modified Date: 24/06/2026
+C++ version used: ISO C++ 14
+Thorlabs DLL version: 1.6.8.27431
+This example demonstrates how to set-up the communication for the Thorlabs
+UMCx controllers with a brushless stage, home it, and move it by 5 mm or degrees.
+*/
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+int main()
+{
+ // Start up XA
+ TLMC_ResultCode startupResult = TLMC_Startup(nullptr);
+ if (startupResult != TLMC_ResultCodes::TLMC_Success)
+ {
+ std::cerr << "SDK Startup failed." << std::endl;
+ return 1;
+ }
+
+ TLMC_DeviceHandle hDevice;
+ const char* deviceSerialNo = "121000020"; // Replace with your device's serial number
+ TLMC_ResultCode resultCode = TLMC_Open(deviceSerialNo, nullptr, TLMC_OperatingModes::TLMC_OperatingMode_Default, &hDevice);
+ if (resultCode != TLMC_ResultCodes::TLMC_Success)
+ {
+ std::cerr << "Failed to open device." << std::endl;
+ std::cerr << "Possible causes: Device is turned off, not connected, or channel serial number is incorrect." << std::endl;
+ TLMC_Shutdown();
+ return 2;
+ }
+ std::cout << "Device opened successfully." << std::endl;
+
+ // Create channel handle and assign channel serial number
+ TLMC_DeviceHandle hChannel;
+ std::string channelSerialNoStr = std::string(deviceSerialNo) + std::to_string(-1);
+ const char* channelSerialNo = channelSerialNoStr.c_str();
+
+ // Open the channel
+ resultCode = TLMC_Open(channelSerialNo, nullptr, TLMC_OperatingModes::TLMC_OperatingMode_Default, &hChannel);
+ if (resultCode != TLMC_ResultCodes::TLMC_Success)
+ {
+ std::cerr << "Failed to open device." << std::endl;
+ std::cerr << "Possible causes: Device is turned off, not connected, or channel serial number is incorrect." << std::endl;
+ TLMC_Shutdown();
+ return 3;
+ }
+ std::cout << "Channel 1 opened successfully." << std::endl;
+
+ // Enable channel 1
+ resultCode = TLMC_SetEnableState(hChannel, TLMC_EnableState::TLMC_Enabled, 60000);
+ if (resultCode != TLMC_ResultCodes::TLMC_Success)
+ {
+ std::cerr << "Failed to enable channel 1." << std::endl;
+ TLMC_Close(hChannel);
+ TLMC_Shutdown();
+ return 4;
+ }
+ std::cout << "Channel 1 enabled successfully." << std::endl;
+
+ // Home channel 1
+ resultCode = TLMC_Home(hChannel, TLMC_InfiniteWait);
+ if (resultCode != TLMC_ResultCodes::TLMC_Success)
+ {
+ std::cerr << "Homing failed." << std::endl;
+ TLMC_Close(hChannel);
+ TLMC_Shutdown();
+ return 5;
+ }
+ std::cout << "Homing successful." << std::endl;
+
+ // Convert 5 mm to device units (physical -> device)
+ double distanceMM = 5.0;
+ int64_t valueInDeviceUnits;
+ resultCode = TLMC_ConvertFromPhysicalToDevice(hChannel, TLMC_ScaleType::TLMC_ScaleType_Distance, TLMC_Unit_Type::TLMC_Unit_Millimetres, distanceMM, &valueInDeviceUnits);
+ if (resultCode != TLMC_ResultCodes::TLMC_Success)
+ {
+ std::cerr << "Conversion failed." << std::endl;
+ TLMC_Close(hChannel);
+ TLMC_Shutdown();
+ return 6;
+ }
+ std::cout << "Conversion from 5 mm successful. Value in device units: " << valueInDeviceUnits << std::endl;
+ std::this_thread::sleep_for(std::chrono::milliseconds(500));
+
+
+ // Absolute move to 5 mm
+ resultCode = TLMC_Move(hChannel, TLMC_MoveMode::TLMC_MoveMode_Absolute, valueInDeviceUnits, 60000);
+ if (resultCode != TLMC_ResultCodes::TLMC_Success)
+ {
+ std::cerr << "Move failed." << std::endl;
+ TLMC_Close(hChannel);
+ TLMC_Shutdown();
+ return 7;
+ }
+ std::cout << "Absolute move successful." << std::endl;
+
+ // Get the current position in device units
+ int32_t currentPosition;
+ resultCode = TLMC_GetPositionCounter(hChannel, ¤tPosition, 60000);
+ if (resultCode != TLMC_ResultCodes::TLMC_Success)
+ {
+ std::cerr << "Failed to get current position." << std::endl;
+ TLMC_Close(hChannel);
+ TLMC_Shutdown();
+ return 8;
+ }
+
+ // Convert the position to physical units and print both position values
+ double valueInPhysicalUnits;
+ TLMC_Unit_Type physicalUnit;
+ resultCode = TLMC_ConvertFromDeviceToPhysical(hChannel, TLMC_ScaleType::TLMC_ScaleType_Distance, currentPosition, &valueInPhysicalUnits, &physicalUnit);
+ if (resultCode != TLMC_ResultCodes::TLMC_Success)
+ {
+ std::cerr << "Conversion failed." << std::endl;
+ TLMC_Close(hChannel);
+ TLMC_Shutdown();
+ return 9;
+ }
+
+ std::cout << "New current position is:\nDevice Units: " << currentPosition << "\nPhysical Units: " << valueInPhysicalUnits << std::endl;
+
+ // Close channel, disconnect and close device, shut down XA
+ if (TLMC_Close(hChannel) != TLMC_ResultCodes::TLMC_Success)
+ std::cerr << "Channel 1 close failed." << std::endl;
+ else
+ std::cout << "Channel 1 closed." << std::endl;
+
+ if (TLMC_Close(hDevice) != TLMC_ResultCodes::TLMC_Success)
+ std::cerr << "Device close failed." << std::endl;
+ else
+ std::cout << "Device closed." << std::endl;
+
+ TLMC_Shutdown();
+}
\ No newline at end of file
diff --git a/C++/XA/UMCx/UMCx.vcxproj b/C++/XA/UMCx/UMCx.vcxproj
new file mode 100644
index 0000000..443390c
--- /dev/null
+++ b/C++/XA/UMCx/UMCx.vcxproj
@@ -0,0 +1,150 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 16.0
+ Win32Proj
+ {36060bf3-e179-4261-a3a2-09b9ad994ef1}
+ UMCtesting
+ 10.0
+
+
+
+ Application
+ true
+ v142
+ Unicode
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+ Application
+ true
+ v142
+ MultiByte
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+ false
+
+
+ true
+ C:\Users\cstroud\source\repos\UMC testing\directory;$(IncludePath)
+ C:\Users\cstroud\source\repos\UMC testing\library;$(LibraryPath)
+
+
+ false
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+ Level3
+ true
+ _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+ tlmc_xa_native.lib;%(AdditionalDependencies)
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/C++/XA/UMCx/UMCx.vcxproj.filters b/C++/XA/UMCx/UMCx.vcxproj.filters
new file mode 100644
index 0000000..253087e
--- /dev/null
+++ b/C++/XA/UMCx/UMCx.vcxproj.filters
@@ -0,0 +1,22 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/C++/XA/UMCx/required_files.txt b/C++/XA/UMCx/required_files.txt
new file mode 100644
index 0000000..4865c84
--- /dev/null
+++ b/C++/XA/UMCx/required_files.txt
@@ -0,0 +1,4 @@
+Copy the following required files to the project folder:
+C:\Program Files\Thorlabs XA\SDK\Native (C, C++)\Libraries\x64\tlmc_xa_native.dll
+C:\Program Files\Thorlabs XA\SDK\Native (C, C++)\Libraries\x64\tlmc_xa_native.lib
+C:\Program Files\Thorlabs XA\SDK\Native (C, C++)\tlmc_xa_native_api.h
\ No newline at end of file