diff --git a/.vscode/settings.json b/.vscode/settings.json index 7a73a41..e4ad736 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,2 +1,3 @@ { + "julia.environmentPath": "c:\\Users\\nanol\\Documents\\GitHub\\MicroscopeControl.jl" } \ No newline at end of file diff --git a/Project.toml b/Project.toml index 6aa0c6e..66408d1 100644 --- a/Project.toml +++ b/Project.toml @@ -20,7 +20,7 @@ Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" [sources] -DAQmx = {url = "https://github.com/LidkeLab/DAQmx.jl.git"} +DAQmx = {rev = "main", url = "https://github.com/LidkeLab/DAQmx.jl.git"} [compat] CEnum = "0.5.0" diff --git a/dev/Project.toml b/dev/Project.toml index 60a21cd..f601f74 100644 --- a/dev/Project.toml +++ b/dev/Project.toml @@ -1,3 +1,6 @@ [deps] MicroscopeControl = "aa70d9ae-4a1e-49fd-870a-8ccfd99f4c3e" Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" + +[sources] +MicroscopeControl = {path = "C:\\Users\\sheng\\.julia\\dev\\MicroscopeControl"} diff --git a/dev/test_fpga.jl b/dev/test_fpga.jl new file mode 100644 index 0000000..a041d0d --- /dev/null +++ b/dev/test_fpga.jl @@ -0,0 +1,46 @@ +using Revise +using MicroscopeControl +using MicroscopeControl.HardwareImplementations.XEM_DAC + + + +fpga = XEM_dac() +#fpga.xem.bitfile = raw"C:\Users\sheng\Documents\Vivado\dac_clk_fp_1\dac_clk_fp_1.runs\impl_1\dac_clk_fp.bit" +fpga.xem.bitfile = raw"C:\Users\sheng\Documents\Vivado\dac_slowclk\dac_slowclk.runs\impl_1\dac_clk_fp.bit" +initialize(fpga.xem) + +va = -1.0 # voltage for channel A +vb = 0.2 # voltage for channel B +vc = 0.2 # voltage for channel C +vd = -0.2 # voltage for channel D + +start(fpga) + +setvoltageA(fpga, va) +setvoltageB(fpga, vb) + +stop(fpga) + + +# generate sawtooth wave on channel A and B + +voltages = collect(-0.005:0.002:0.005) +cyclenum = 20 +start(fpga) +for cycle in 1:cyclenum + for v in voltages + #setvoltageA(fpga, v) + setvoltageB(fpga, v) + #setvoltage(daq,t, v) + sleep(0.001) + end +end +stop(fpga) + + +shutdown(fpga.xem) + + + + + diff --git a/dev/test_fpga_eod.jl b/dev/test_fpga_eod.jl new file mode 100644 index 0000000..efe733e --- /dev/null +++ b/dev/test_fpga_eod.jl @@ -0,0 +1,73 @@ + + +using Revise +using MicroscopeControl +using MicroscopeControl.HardwareImplementations.XEM_DAC + + + + +fpga = XEM_dac() +#fpga.xem.bitfile = raw"C:\Users\sheng\Documents\Vivado\dac_slowclk_eod\dac_slowclk_eod.runs\dac_eod_dac1280ns.bit" +fpga.xem.bitfile = raw"C:\Users\sheng\Documents\Vivado\dac_slowclk_eod\dac_slowclk_eod.runs\dac_eod_dac80ns.bit" +#fpga.xem.bitfile = raw"C:\Users\sheng\Documents\Vivado\dac_slowclk_eod\dac_slowclk_eod.runs\impl_1\dac_eod.bit" +initialize(fpga.xem) + +va = 0.0 # voltage for channel A +vb = 0.0 # voltage for channel B +vc = 0.0 # voltage for channel C +vd = 0.0 # voltage for channel D + +va = -0.01 +vb = -0.015 +vc = -0.02 +vd = -0.025 + +#code = XEM_DAC.volts_to_code(0.0) + +setvoltageD(fpga, 0.5) + + +setvoltageAll(fpga, va,vb,vc,vd) + +start(fpga) + + + + +stop(fpga) + + +# generate sawtooth wave on channel A and B + + + + + +voltages = collect(-0.005:0.002:0.005) +cyclenum = 20 +start(fpga) +for cycle in 1:cyclenum + for v in voltages + #setvoltageA(fpga, v) + setvoltageB(fpga, v) + #setvoltage(daq,t, v) + sleep(0.001) + end +end +stop(fpga) + + + + +shutdown(fpga.xem) + + + + + + + + + + diff --git a/dev/test_fpga_loc.jl b/dev/test_fpga_loc.jl new file mode 100644 index 0000000..5cbf824 --- /dev/null +++ b/dev/test_fpga_loc.jl @@ -0,0 +1,96 @@ +using Revise +using MicroscopeControl +using MicroscopeControl.HardwareImplementations.OK_XEM + + + + +fpga = XEM() +fpga.bitfile = raw"C:\Users\sheng\Documents\Vivado\test_div\test_div.runs\impl_1\normalize_fp.bit" +initialize(fpga) + + +#---------------------------------------- +# Endpoint Constants +#---------------------------------------- +const EP_WIREIN_CTRL = 0x00 +const EP_WIREIN_X0 = 0x01 +const EP_WIREIN_X1 = 0x02 +const EP_WIREIN_X2 = 0x03 + +const EP_WIREOUT_Y0 = 0x20 +const EP_WIREOUT_Y1 = 0x21 +const EP_WIREOUT_ST = 0x22 + +#---------------------------------------- +# Control Constants +#---------------------------------------- +const CTRL_VALID_ON = UInt32(0x00000001) +const CTRL_VALID_OFF = UInt32(0x00000000) + +#---------------------------------------- +# Helper: convert 32-bit → signed 16-bit +#---------------------------------------- +function to_int16(x::UInt32) + val = x & 0xFFFF # keep only lower 16 bits + return reinterpret(Int16, UInt16(val)) +end + +function q14_to_float(x::UInt32) + val = to_int16(x) # signed 16-bit + return Float64(val) / 16384 # 2^14 = 16384 +end +#---------------------------------------- +# One transaction +#---------------------------------------- +function send_and_read(fpga::XEM, x0::Int16, x1::Int16, x2::Int16) + #x0 = Int16(100) + #x1 = Int16(200) + #x2 = Int16(20) + + setwirein(fpga, EP_WIREIN_X0, UInt32(reinterpret(UInt16, x0))) + setwirein(fpga, EP_WIREIN_X1, UInt32(reinterpret(UInt16, x1))) + setwirein(fpga, EP_WIREIN_X2, UInt32(reinterpret(UInt16, x2))) + + # Pulse valid_in using constants + setwirein(fpga, EP_WIREIN_CTRL, CTRL_VALID_ON) + sleep(0.001) + setwirein(fpga, EP_WIREIN_CTRL, CTRL_VALID_OFF) + sleep(0.0005) + + status = getwireout(fpga, EP_WIREOUT_ST) + + + y0_raw = getwireout(fpga, EP_WIREOUT_Y0) + y1_raw = getwireout(fpga, EP_WIREOUT_Y1) + + y0_q14 = to_int16(y0_raw) + y1_q14 = to_int16(y1_raw) + + y0_real = q14_to_float(y0_raw) + y1_real = q14_to_float(y1_raw) + + println("INPUT : x0=$x0 x1=$x1 x2=$x2") + println("OUTPUT : y0_raw=0x", string(y0_raw, base=16), " y1_raw=0x", string(y1_raw, base=16)) + println("OUTPUT : y0_q14=$y0_q14 y1_q14=$y1_q14 ") + println("OUTPUT : y0_real=$(round(y0_real, sigdigits=4)) y1_real=$(round(y1_real, sigdigits=4)) (ready=$status)") + println("--------------------------------------") + + + +end + +#---------------------------------------- +# Main test +#---------------------------------------- + + +println("Starting normalize_fp test...\n") + +send_and_read(fpga, Int16(20), Int16(50), Int16(20)) +send_and_read(fpga, Int16(40), Int16(20), Int16(70)) +send_and_read(fpga, Int16(10), Int16(10), Int16(10)) + +println("Test completed.") + +shutdown(fpga) \ No newline at end of file diff --git a/dev/test_nidaq.jl b/dev/test_nidaq.jl new file mode 100644 index 0000000..2b5d711 --- /dev/null +++ b/dev/test_nidaq.jl @@ -0,0 +1,42 @@ +using Revise +using MicroscopeControl +using MicroscopeControl.HardwareImplementations.NIDAQcard + + + + + +daq = NIdaq() # the type of daq is NIdaq + + + + +devs = showdevices(daq) +channelsAO = showchannels(daq,"AO",devs[1]) + +t = createtask(daq,"AO",channelsAO[1]) # the type of t is Task +setvoltage(daq,t, 0.0) # the maximum voltage is 5.0 V. + +t1 = createtask(daq,"AO",channelsAO[2]) # the type of t is Task +setvoltage(daq,t1, -1.0) # the maximum voltage is 5.0 V. + +channelsDO = showchannels(daq,"DO",devs[1]) +t2 = createtask(daq,"DO",channelsDO[1]) # the type of t is Task + +setvoltage(daq,t2, 1.0) + +deletetask(daq,t2) + +voltages = collect(-0.01:0.005:0.01) +cyclenum = 10 + +for cycle in 1:cyclenum + for v in voltages + setvoltage(daq,t, v) + sleep(0.1) + end +end + + +deletetask(daq,t) + diff --git a/dev/test_okFP.jl b/dev/test_okFP.jl new file mode 100644 index 0000000..92abe59 --- /dev/null +++ b/dev/test_okFP.jl @@ -0,0 +1,92 @@ + +include("constants_okFP.jl") +include("functions_okFP.jl") + +const okFP = "C:\\Program Files\\Opal Kelly\\FrontPanelUSB\\API\\lib\\x64\\okFrontPanel.dll" + +devicehandle = okFrontPanel_Construct() +num = okFrontPanel_GetDeviceCount(devicehandle) +if num == 0 + println("No fpga board found.") + return +end + +# find device model and serial number +fpgalabel = string(okFrontPanel_GetDeviceListModel(devicehandle, 0)) +println("FPGA board found: " * fpgalabel) + +buffersize = 128 +serialstring = zeros(UInt8, buffersize) +okFrontPanel_GetDeviceListSerial(devicehandle, 0, serialstring) +serialstring = filter(x -> x != 0x00, serialstring) + +# open the device +err = okFrontPanel_OpenBySerial(devicehandle, serialstring) +if err != ok_ErrorCode(0) + println("Failed to open FPGA board: " * string(err)) + return +end +serialnumber = String(serialstring) +println("FPGA board serial number: " * serialnumber) + +# configure the FPGA +bitfile = raw"C:\Users\sheng\Documents\Vivado\dac_clk_fp_1\dac_clk_fp_1.runs\impl_1\dac_clk_fp.bit" +err = okFrontPanel_ConfigureFPGA(devicehandle, bitfile) +if err != ok_ErrorCode(0) + println("Failed to configure FPGA: " * string(err)) + return +end + + + +const EP_WIREIN_A = 0x01 +const EP_WIREIN_B = 0x02 +const EP_WIREIN_C = 0x03 +const EP_WIREIN_D = 0x04 + +const EP_WIREIN_START = 0x05 +const BIT_START = 0x01 +const BIT_STOP = 0x00 + +const EP_TRIGGEROUT_CYCLEEND = 0x60 +const TRIG_BIT_CYCLEEND = 0x01 + +# Voltage-to-code helper (adjust for DAC8814 mode) +function volts_to_code(v::Float64; vmin::Float64=-10.0, vmax::Float64=10.0) + if v < vmin || v > vmax + error("Voltage $v V out of range for Vmin=$vmin V and Vmax=$vmax V") + end + return UInt32(round(65535 - ((v - vmin) / (vmax - vmin)) * 65535)) +end + +# Main routine + + +# Example voltages +a = volts_to_code(-0.205) +b = volts_to_code(0.205) +c = volts_to_code(0.405) +d = volts_to_code(-0.405) + +# Write voltages + +err = okFrontPanel_SetWireInValue(devicehandle, EP_WIREIN_A, a, 0xFFFF) +err = okFrontPanel_SetWireInValue(devicehandle, EP_WIREIN_B, b, 0xFFFF) +err = okFrontPanel_SetWireInValue(devicehandle, EP_WIREIN_C, c, 0xFFFF) +err = okFrontPanel_SetWireInValue(devicehandle, EP_WIREIN_D, d, 0xFFFF) +err = okFrontPanel_UpdateWireIns(devicehandle) + +# start +err = okFrontPanel_SetWireInValue(devicehandle, EP_WIREIN_START, BIT_START, 0xFFFF) +err = okFrontPanel_UpdateWireIns(devicehandle) +# stop +err = okFrontPanel_SetWireInValue(devicehandle, EP_WIREIN_START, BIT_STOP, 0xFFFF) +err = okFrontPanel_UpdateWireIns(devicehandle) + +#err = okFrontPanel_ActivateTriggerIn(devicehandle, EP_TRIGGERIN_START, TRIG_BIT_START) + +#err = okFrontPanel_UpdateTriggerOuts(devicehandle) + +#iscycleend = okFrontPanel_IsTriggered(devicehandle, EP_TRIGGEROUT_CYCLEEND, TRIG_BIT_CYCLEEND) + +err = okFrontPanel_Destruct(devicehandle) diff --git a/dev/test_smaract_stage.jl b/dev/test_smaract_stage.jl new file mode 100644 index 0000000..6c91895 --- /dev/null +++ b/dev/test_smaract_stage.jl @@ -0,0 +1,18 @@ +using Pkg +Pkg.activate("C:\\Users\\nanol\\.julia\\dev\\MicroscopeControl.jl") +using MicroscopeControl + +stage = MCS2Stage( + stagelabel = "SmarAct MCS2", + n_channels = 3, + channel_ids = Int32[0, 1, 2], +) + +initialize(stage) + +# move_um!(stage, [10.0, 5.0 ,0.0]) + +stage.range_x = (-20_000.0, 20_000.0) # µm, since these fields are in micrometres, software limits only, not hardware limits. The hardware limits are in the device's firmware and cannot be changed from software. +stage.range_y = (-20_000.0, 20_000.0) + +MicroscopeControl.HardwareInterfaces.StageInterface.gui(stage) \ No newline at end of file diff --git a/src/hardware_implementations/HardwareImplementations.jl b/src/hardware_implementations/HardwareImplementations.jl index d8bb3d5..646bc45 100644 --- a/src/hardware_implementations/HardwareImplementations.jl +++ b/src/hardware_implementations/HardwareImplementations.jl @@ -33,6 +33,9 @@ include("mcl_stage/MadCityLabs.jl") include("pi_N472/PI_N472.jl") @reexport using .PI_N472 +include("smaract_stage/MCS2Stage_module.jl") +@reexport using .MCS2Stage_mod + # DAQ implementation (must come before modules that depend on it) include("nidaq/NIDAQcard.jl") @reexport using .NIDAQcard @@ -61,6 +64,10 @@ include("ok_xem/OK_XEM.jl") include("meadowlark_slm/Meadowlark.jl") @reexport using .Meadowlark +# FPGA DAC implementation +include("xem_dac/XEM_DAC.jl") +@reexport using .XEM_DAC + # Work in progress - uncomment when ready # include("triggerscope/Triggerscope.jl") # @reexport using .Triggerscope diff --git a/src/hardware_implementations/ok_xem/OK_XEM.jl b/src/hardware_implementations/ok_xem/OK_XEM.jl index f9fdcbb..0dfe8ae 100644 --- a/src/hardware_implementations/ok_xem/OK_XEM.jl +++ b/src/hardware_implementations/ok_xem/OK_XEM.jl @@ -11,6 +11,6 @@ module OK_XEM include("interface_methods.jl") export XEM - export setexposure, enable,setupIO #, initialize + export setexposure, enable,setupIO, setwirein, activetriggerin, getwireout #, initialize end \ No newline at end of file diff --git a/src/hardware_implementations/ok_xem/interface_methods.jl b/src/hardware_implementations/ok_xem/interface_methods.jl index a286c9d..6db303e 100644 --- a/src/hardware_implementations/ok_xem/interface_methods.jl +++ b/src/hardware_implementations/ok_xem/interface_methods.jl @@ -93,4 +93,41 @@ end function shutdown(fpga::XEM) okFrontPanel_Destruct(fpga.devicehandle) return nothing +end + +function setwirein(fpga::XEM, epaddr::UInt8, value::UInt32) + err = okFrontPanel_SetWireInValue(fpga.devicehandle, epaddr, value, 0xFFFF) + if err != ok_ErrorCode(0) + println("Failed to set wire in value: "*string(err)) + return + end + err = okFrontPanel_UpdateWireIns(fpga.devicehandle) + if err != ok_ErrorCode(0) + println("Failed to update wire ins: "*string(err)) + return + end + return nothing +end + +function activetriggerin(fpga::XEM, epaddr::UInt8, bitmask::UInt32) + err = okFrontPanel_ActivateTriggerIn(fpga.devicehandle, epaddr, bitmask) + if err != ok_ErrorCode(0) + println("Failed to activate trigger in: "*string(err)) + return + end + return nothing +end + +function getwireout(fpga::XEM, epaddr::UInt8) + # Update wire outs first (required!) + err = okFrontPanel_UpdateWireOuts(fpga.devicehandle) + if err != ok_ErrorCode(0) + println("Failed to update wire outs: " * string(err)) + return nothing + end + + # Read value + value = okFrontPanel_GetWireOutValue(fpga.devicehandle, epaddr) + + return UInt32(value) end \ No newline at end of file diff --git a/src/hardware_implementations/smaract_stage/MCS2Stage_module.jl b/src/hardware_implementations/smaract_stage/MCS2Stage_module.jl new file mode 100644 index 0000000..c7a0428 --- /dev/null +++ b/src/hardware_implementations/smaract_stage/MCS2Stage_module.jl @@ -0,0 +1,51 @@ +module MCS2Stage_mod + +using ...MicroscopeControl.HardwareInterfaces.StageInterface +import ...MicroscopeControl: export_state, initialize, shutdown + +# Path to the SmarAct DLL +const SmarAct = "C:\\Windows\\System32\\SmarActCTL.dll" + +# Load sub-files in dependency order +# 1. Constants first — everything else depends on the type aliases +include("constants_smaract.jl") # SA_CTL_* constants and type aliases + +# 2. Low-level DLL wrappers +include("functions_smaract.jl") # ccall wrappers for every SDK function + +# 3. Struct definition (needs the type aliases from constants) +include("types_smaract.jl") # MCS2Stage struct + constructor + +# 4. Motion helpers (needs the struct + functions) +include("helper_smaract.jl") + +# 5. High-level interface methods (needs the helpers) +include("interface_methods_smaract.jl") + +# 6. Adapts MCS2Stage onto the shared StageInterface contract +include("stageinterface_bridge_smaract.jl") + +# Public exports +export MCS2Stage # the stage struct + constructor + +# Interface methods (exports: initialize, shutdown, gui) +export initialize! +export shutdown! +export move!, move_um! +export getposition! +export home! +export stopmotion! +export export_state + +# Motion helpers +export find_reference! +export find_travel_range! +export set_velocity! +export set_acceleration! +export query_positions! +export stop_all!, stop_channel! + +# GUI +export gui + +end diff --git a/src/hardware_implementations/smaract_stage/constants_smaract.jl b/src/hardware_implementations/smaract_stage/constants_smaract.jl new file mode 100644 index 0000000..5466ac3 --- /dev/null +++ b/src/hardware_implementations/smaract_stage/constants_smaract.jl @@ -0,0 +1,1498 @@ +const SA_CTL_DeviceHandle_t = UInt32 + +const SA_CTL_TransmitHandle_t = UInt32 + +const SA_CTL_StreamHandle_t = UInt32 + +const SA_CTL_RequestID_t = UInt8 + +const SA_CTL_PropertyKey_t = UInt32 + +const SA_CTL_Result_t = UInt32 + +struct SA_CTL_Event_t + data::NTuple{32, UInt8} +end + +function Base.getproperty(x::Ptr{SA_CTL_Event_t}, f::Symbol) + f === :idx && return Ptr{UInt32}(x + 0) + f === :type && return Ptr{UInt32}(x + 4) + f === :i32 && return Ptr{Int32}(x + 8) + f === :i64 && return Ptr{Int64}(x + 8) + f === :unused && return Ptr{NTuple{24, UInt8}}(x + 8) + return getfield(x, f) +end + +function Base.getproperty(x::SA_CTL_Event_t, f::Symbol) + r = Ref{SA_CTL_Event_t}(x) + ptr = Base.unsafe_convert(Ptr{SA_CTL_Event_t}, r) + fptr = getproperty(ptr, f) + GC.@preserve r unsafe_load(fptr) +end + +function Base.setproperty!(x::Ptr{SA_CTL_Event_t}, f::Symbol, v) + unsafe_store!(getproperty(x, f), v) +end + +function Base.propertynames(x::SA_CTL_Event_t, private::Bool = false) + (:idx, :type, :i32, :i64, :unused, if private + fieldnames(typeof(x)) + else + () + end...) +end + +const SA_CTL_INFINITE = 0xffffffff + +const SA_CTL_HOLD_TIME_INFINITE = -1 + +const SA_CTL_FALSE = 0x00 + +const SA_CTL_TRUE = 0x01 + +const SA_CTL_DISABLED = 0x00 + +const SA_CTL_ENABLED = 0x01 + +const SA_CTL_NON_INVERTED = 0x00 + +const SA_CTL_INVERTED = 0x01 + +const SA_CTL_FORWARD_DIRECTION = 0x00 + +const SA_CTL_BACKWARD_DIRECTION = 0x01 + +const SA_CTL_EITHER_DIRECTION = 0x02 + +const SA_CTL_STRING_MAX_LENGTH = 63 + +const SA_CTL_REQUEST_ID_MAX_COUNT = 240 + +const SA_CTL_INTERFACE_USB = 0x0001 + +const SA_CTL_INTERFACE_ETHERNET = 0x0002 + +const SA_CTL_STICK_SLIP_PIEZO_DRIVER = 0x0001 + +const SA_CTL_MAGNETIC_DRIVER = 0x0002 + +const SA_CTL_PIEZO_SCANNER_DRIVER = 0x0003 + +const SA_CTL_EVENT_NONE = 0x0000 + +const SA_CTL_EVENT_MOVEMENT_FINISHED = 0x0001 + +const SA_CTL_EVENT_SENSOR_STATE_CHANGED = 0x0002 + +const SA_CTL_EVENT_REFERENCE_FOUND = 0x0003 + +const SA_CTL_EVENT_FOLLOWING_ERR_LIMIT = 0x0004 + +const SA_CTL_EVENT_HOLDING_ABORTED = 0x0005 + +const SA_CTL_EVENT_POSITIONER_TYPE_CHANGED = 0x0006 + +const SA_CTL_EVENT_PHASING_FINISHED = 0x0007 + +const SA_CTL_EVENT_AMP_STATE_CHANGED = 0x000a + +const SA_CTL_EVENT_TRAJECTORY_STARTED = 0x000b + +const SA_CTL_EVENT_TACTILE_SENSING_TRIGGERED = 0x000c + +const SA_CTL_EVENT_SM_STATE_CHANGED = 0x4000 + +const SA_CTL_EVENT_OVER_TEMPERATURE = 0x4001 + +const SA_CTL_EVENT_HIGH_VOLTAGE_OVERLOAD = 0x4002 + +const SA_CTL_EVENT_POWER_SUPPLY_OVERLOAD = 0x4002 + +const SA_CTL_EVENT_POWER_SUPPLY_FAILURE = 0x4003 + +const SA_CTL_EVENT_FAN_FAILURE_STATE_CHANGED = 0x4004 + +const SA_CTL_EVENT_CAPTURE_BUFFER_STATE_CHANGED = 0x4005 + +const SA_CTL_EVENT_ADJUSTMENT_FINISHED = 0x4010 + +const SA_CTL_EVENT_ADJUSTMENT_STATE_CHANGED = 0x4011 + +const SA_CTL_EVENT_ADJUSTMENT_UPDATE = 0x4012 + +const SA_CTL_EVENT_ALIGNMENT_IN_RANGE = 0x4020 + +const SA_CTL_EVENT_DIGITAL_INPUT_CHANGED = 0x4040 + +const SA_CTL_EVENT_SM_DIGITAL_INPUT_CHANGED = 0x4041 + +const SA_CTL_EVENT_STREAM_FINISHED = 0x8000 + +const SA_CTL_EVENT_STREAM_READY = 0x8001 + +const SA_CTL_EVENT_STREAM_TRIGGERED = 0x8002 + +const SA_CTL_EVENT_CMD_GROUP_TRIGGERED = 0x8010 + +const SA_CTL_EVENT_HM_STATE_CHANGED = 0x8020 + +const SA_CTL_EVENT_EMERGENCY_STOP_TRIGGERED = 0x8030 + +const SA_CTL_EVENT_EXT_INPUT_TRIGGERED = 0x8040 + +const SA_CTL_EVENT_BUS_RESYNC_TRIGGERED = 0x8050 + +const SA_CTL_EVENT_UNKNOWN_COMMAND_RECEIVED = 0x8051 + +const SA_CTL_EVENT_REQUEST_READY = 0xf000 + +const SA_CTL_EVENT_CONNECTION_LOST = 0xf001 + +const SA_CTL_EVENT_PARAM_DETACHED = 0x00000000 + +const SA_CTL_EVENT_PARAM_ATTACHED = 0x00000001 + +const SA_CTL_EVENT_PARAM_DISABLED = 0x00000000 + +const SA_CTL_EVENT_PARAM_ENABLED = 0x00000001 + +const SA_CTL_EVENT_REQ_READY_TYPE_READ = 0x00 + +const SA_CTL_EVENT_REQ_READY_TYPE_WRITE = 0x01 + +const SA_CTL_EVENT_PARAM_RESULT_MASK = 0x0000ffff + +const SA_CTL_EVENT_PARAM_INDEX_MASK = 0x00ff0000 + +const SA_CTL_EVENT_PARAM_HANDLE_MASK = 0xff000000 + +const SA_CTL_EVENT_REQ_READY_ID_MASK = 0x00000000000000ff + +const SA_CTL_EVENT_REQ_READY_TYPE_MASK = 0x000000000000ff00 + +const SA_CTL_EVENT_REQ_READY_DATA_TYPE_MASK = 0x0000000000ff0000 + +const SA_CTL_EVENT_REQ_READY_ARRAY_SIZE_MASK = 0x00000000ff000000 + +const SA_CTL_EVENT_REQ_READY_PROPERTY_KEY_MASK = 0xffffffff00000000 + +const SA_CTL_ERROR_NONE = 0x0000 + +const SA_CTL_ERROR_UNKNOWN_COMMAND = 0x0001 + +const SA_CTL_ERROR_INVALID_PACKET_SIZE = 0x0002 + +const SA_CTL_ERROR_TIMEOUT = 0x0004 + +const SA_CTL_ERROR_INVALID_PROTOCOL = 0x0005 + +const SA_CTL_ERROR_BUFFER_UNDERFLOW = 0x000c + +const SA_CTL_ERROR_BUFFER_OVERFLOW = 0x000d + +const SA_CTL_ERROR_INVALID_FRAME_SIZE = 0x000e + +const SA_CTL_ERROR_INVALID_PACKET = 0x0010 + +const SA_CTL_ERROR_INVALID_KEY = 0x0012 + +const SA_CTL_ERROR_INVALID_PARAMETER = 0x0013 + +const SA_CTL_ERROR_INVALID_DATA_TYPE = 0x0016 + +const SA_CTL_ERROR_INVALID_DATA = 0x0017 + +const SA_CTL_ERROR_HANDLE_LIMIT_REACHED = 0x0018 + +const SA_CTL_ERROR_ABORTED = 0x0019 + +const SA_CTL_ERROR_INVALID_DEVICE_INDEX = 0x0020 + +const SA_CTL_ERROR_INVALID_MODULE_INDEX = 0x0021 + +const SA_CTL_ERROR_INVALID_CHANNEL_INDEX = 0x0022 + +const SA_CTL_ERROR_PERMISSION_DENIED = 0x0023 + +const SA_CTL_ERROR_COMMAND_NOT_GROUPABLE = 0x0024 + +const SA_CTL_ERROR_MOVEMENT_LOCKED = 0x0025 + +const SA_CTL_ERROR_SYNC_FAILED = 0x0026 + +const SA_CTL_ERROR_INVALID_ARRAY_SIZE = 0x0027 + +const SA_CTL_ERROR_OVERRANGE = 0x0028 + +const SA_CTL_ERROR_INVALID_CONFIGURATION = 0x0029 + +const SA_CTL_ERROR_INVALID_GROUP_HANDLE = 0x002a + +const SA_CTL_ERROR_NO_HM_PRESENT = 0x0100 + +const SA_CTL_ERROR_NO_IOM_PRESENT = 0x0101 + +const SA_CTL_ERROR_NO_SM_PRESENT = 0x0102 + +const SA_CTL_ERROR_NO_SENSOR_PRESENT = 0x0103 + +const SA_CTL_ERROR_SENSOR_DISABLED = 0x0104 + +const SA_CTL_ERROR_POWER_SUPPLY_DISABLED = 0x0105 + +const SA_CTL_ERROR_AMPLIFIER_DISABLED = 0x0106 + +const SA_CTL_ERROR_INVALID_SENSOR_MODE = 0x0107 + +const SA_CTL_ERROR_INVALID_ACTUATOR_MODE = 0x0108 + +const SA_CTL_ERROR_INVALID_INPUT_TRIG_MODE = 0x0109 + +const SA_CTL_ERROR_INVALID_CONTROL_OPTIONS = 0x010a + +const SA_CTL_ERROR_INVALID_REFERENCE_TYPE = 0x010b + +const SA_CTL_ERROR_INVALID_ADJUSTMENT_STATE = 0x010c + +const SA_CTL_ERROR_INVALID_INFO_TYPE = 0x010d + +const SA_CTL_ERROR_NO_FULL_ACCESS = 0x010e + +const SA_CTL_ERROR_ADJUSTMENT_FAILED = 0x010f + +const SA_CTL_ERROR_MOVEMENT_OVERRIDDEN = 0x0110 + +const SA_CTL_ERROR_NOT_CALIBRATED = 0x0111 + +const SA_CTL_ERROR_NOT_REFERENCED = 0x0112 + +const SA_CTL_ERROR_NOT_ADJUSTED = 0x0113 + +const SA_CTL_ERROR_SENSOR_TYPE_NOT_SUPPORTED = 0x0114 + +const SA_CTL_ERROR_CONTROL_LOOP_INPUT_DISABLED = 0x0115 + +const SA_CTL_ERROR_INVALID_CONTROL_LOOP_INPUT = 0x0116 + +const SA_CTL_ERROR_UNEXPECTED_SENSOR_DATA = 0x0117 + +const SA_CTL_ERROR_NOT_PHASED = 0x0118 + +const SA_CTL_ERROR_POSITIONER_FAULT = 0x0119 + +const SA_CTL_ERROR_DRIVER_FAULT = 0x011a + +const SA_CTL_ERROR_POSITIONER_TYPE_NOT_SUPPORTED = 0x011b + +const SA_CTL_ERROR_POSITIONER_TYPE_NOT_IDENTIFIED = 0x011c + +const SA_CTL_ERROR_POSITIONER_TYPE_NOT_WRITEABLE = 0x011e + +const SA_CTL_ERROR_CAPTURE_RUNNING = 0x011f + +const SA_CTL_ERROR_DATA_BUFFER_EMPTY = 0x0120 + +const SA_CTL_ERROR_INVALID_ACTUATOR_TYPE = 0x0121 + +const SA_CTL_ERROR_NO_COMMUTATION_SENSOR_PRESENT = 0x0122 + +const SA_CTL_ERROR_AMPLIFIER_LOCKED = 0x0123 + +const SA_CTL_ERROR_WRITE_ACCESS_LOCKED = 0x0124 + +const SA_CTL_ERROR_UNEXPECTED_SCAN_RANGE = 0x0125 + +const SA_CTL_ERROR_INVALID_RES_FREQ_CONFIGURATION = 0x0126 + +const SA_CTL_ERROR_DATA_BUFFER_FULL = 0x0127 + +const SA_CTL_ERROR_WFG_BUFFER_NOT_READY = 0x0128 + +const SA_CTL_ERROR_OPERATING_VOLTAGE_EXCEEDED = 0x0129 + +const SA_CTL_ERROR_BUSY_MOVING = 0x0150 + +const SA_CTL_ERROR_BUSY_CALIBRATING = 0x0151 + +const SA_CTL_ERROR_BUSY_REFERENCING = 0x0152 + +const SA_CTL_ERROR_BUSY_ADJUSTING = 0x0153 + +const SA_CTL_ERROR_BUSY_CHANGING_AMP_STATE = 0x0155 + +const SA_CTL_ERROR_END_STOP_REACHED = 0x0200 + +const SA_CTL_ERROR_FOLLOWING_ERR_LIMIT = 0x0201 + +const SA_CTL_ERROR_RANGE_LIMIT_REACHED = 0x0202 + +const SA_CTL_ERROR_POSITIONER_OVERLOAD = 0x0203 + +const SA_CTL_ERROR_MODULE_LINK_FAILURE = 0x0204 + +const SA_CTL_ERROR_POWER_SUPPLY_FAILURE = 0x0205 + +const SA_CTL_ERROR_OVER_TEMPERATURE = 0x0206 + +const SA_CTL_ERROR_POWER_SUPPLY_OVERLOAD = 0x0208 + +const SA_CTL_ERROR_CONTROL_LOOP_UNSTABLE = 0x0209 + +const SA_CTL_ERROR_TACTILE_SENSING_TRIGGERED = 0x020a + +const SA_CTL_ERROR_INVALID_STREAM_HANDLE = 0x0300 + +const SA_CTL_ERROR_INVALID_STREAM_CONFIGURATION = 0x0301 + +const SA_CTL_ERROR_INSUFFICIENT_FRAMES = 0x0302 + +const SA_CTL_ERROR_BUSY_STREAMING = 0x0303 + +const SA_CTL_ERROR_HM_INVALID_SLOT_INDEX = 0x0400 + +const SA_CTL_ERROR_HM_INVALID_CHANNEL_INDEX = 0x0401 + +const SA_CTL_ERROR_HM_INVALID_GROUP_INDEX = 0x0402 + +const SA_CTL_ERROR_HM_INVALID_CH_GRP_INDEX = 0x0403 + +const SA_CTL_ERROR_INTERNAL_COMMUNICATION = 0x0500 + +const SA_CTL_ERROR_EEPROM_BUFFER_OVERFLOW = 0x0501 + +const SA_CTL_ERROR_FEATURE_NOT_SUPPORTED = 0x7ffd + +const SA_CTL_ERROR_FEATURE_NOT_IMPLEMENTED = 0x7ffe + +const SA_CTL_ERROR_DEVICE_LIMIT_REACHED = 0xf000 + +const SA_CTL_ERROR_INVALID_LOCATOR = 0xf001 + +const SA_CTL_ERROR_INITIALIZATION_FAILED = 0xf002 + +const SA_CTL_ERROR_NOT_INITIALIZED = 0xf003 + +const SA_CTL_ERROR_COMMUNICATION_FAILED = 0xf004 + +const SA_CTL_ERROR_INVALID_QUERYBUFFER_SIZE = 0xf006 + +const SA_CTL_ERROR_INVALID_DEVICE_HANDLE = 0xf007 + +const SA_CTL_ERROR_INVALID_TRANSMIT_HANDLE = 0xf008 + +const SA_CTL_ERROR_UNEXPECTED_PACKET_RECEIVED = 0xf00f + +const SA_CTL_ERROR_CANCELED = 0xf010 + +const SA_CTL_ERROR_DRIVER_FAILED = 0xf013 + +const SA_CTL_ERROR_BUFFER_LIMIT_REACHED = 0xf016 + +const SA_CTL_ERROR_INVALID_PROTOCOL_VERSION = 0xf017 + +const SA_CTL_ERROR_DEVICE_RESET_FAILED = 0xf018 + +const SA_CTL_ERROR_BUFFER_EMPTY = 0xf019 + +const SA_CTL_ERROR_DEVICE_NOT_FOUND = 0xf01a + +const SA_CTL_ERROR_THREAD_LIMIT_REACHED = 0xf01b + +const SA_CTL_ERROR_NO_APPLICATION = 0xf01c + +const SA_CTL_DTYPE_UINT16 = 0x03 + +const SA_CTL_DTYPE_INT32 = 0x06 + +const SA_CTL_DTYPE_INT64 = 0x0e + +const SA_CTL_DTYPE_FLOAT32 = 0x10 + +const SA_CTL_DTYPE_FLOAT64 = 0x11 + +const SA_CTL_DTYPE_STRING = 0x12 + +const SA_CTL_DTYPE_NONE = 0xff + +const SA_CTL_UNIT_NONE = 0x00000000 + +const SA_CTL_UNIT_PERCENT = 0x00000001 + +const SA_CTL_UNIT_METER = 0x00000002 + +const SA_CTL_UNIT_DEGREE = 0x00000003 + +const SA_CTL_UNIT_SECOND = 0x00000004 + +const SA_CTL_UNIT_HERTZ = 0x00000005 + +const SA_CTL_PKEY_NUMBER_OF_CHANNELS = 0x020f0017 + +const SA_CTL_PKEY_NUMBER_OF_BUS_MODULES = 0x020f0016 + +const SA_CTL_PKEY_INTERFACE_TYPE = 0x020f0066 + +const SA_CTL_PKEY_DEVICE_STATE = 0x020f000f + +const SA_CTL_PKEY_DEVICE_SERIAL_NUMBER = 0x020f005e + +const SA_CTL_PKEY_DEVICE_NAME = 0x020f003d + +const SA_CTL_PKEY_EMERGENCY_STOP_MODE = 0x020f0088 + +const SA_CTL_PKEY_DEFAULT_EMERGENCY_STOP_MODE = 0x020f0116 + +const SA_CTL_PKEY_NETWORK_DISCOVER_MODE = 0x020f0159 + +const SA_CTL_PKEY_NETWORK_DHCP_TIMEOUT = 0x020f015c + +const SA_CTL_PKEY_MIN_FAN_LEVEL = 0x020f00db + +const SA_CTL_PKEY_POWER_SUPPLY_ENABLED = 0x02030010 + +const SA_CTL_PKEY_NUMBER_OF_BUS_MODULE_CHANNELS = 0x02030017 + +const SA_CTL_PKEY_MODULE_TYPE = 0x02030066 + +const SA_CTL_PKEY_AMPLIFIER_OUTPUT_VOLTAGE = 0x02030080 + +const SA_CTL_PKEY_MODULE_STATE = 0x0203000f + +const SA_CTL_PKEY_MODULE_TIMESTAMP = 0x0203012c + +const SA_CTL_PKEY_STARTUP_OPTIONS = 0x0a02005d + +const SA_CTL_PKEY_AMPLIFIER_ENABLED = 0x0302000d + +const SA_CTL_PKEY_AMPLIFIER_MODE = 0x030200bf + +const SA_CTL_PKEY_POSITIONER_CONTROL_OPTIONS = 0x0302005d + +const SA_CTL_PKEY_ACTUATOR_MODE = 0x03020019 + +const SA_CTL_PKEY_CONTROL_LOOP_INPUT = 0x03020018 + +const SA_CTL_PKEY_SENSOR_INPUT_SELECT = 0x0302009d + +const SA_CTL_PKEY_SENSOR_INVERSION = 0x0508000e + +const SA_CTL_PKEY_POSITIONER_TYPE = 0x0302003c + +const SA_CTL_PKEY_POSITIONER_TYPE_NAME = 0x0302003d + +const SA_CTL_PKEY_MOVE_MODE = 0x03050087 + +const SA_CTL_PKEY_CHANNEL_TYPE = 0x02020066 + +const SA_CTL_PKEY_CHANNEL_STATE = 0x0305000f + +const SA_CTL_PKEY_POSITION = 0x0305001d + +const SA_CTL_PKEY_TARGET_POSITION = 0x0305001e + +const SA_CTL_PKEY_SCAN_POSITION = 0x0305001f + +const SA_CTL_PKEY_SCAN_VELOCITY = 0x0305002a + +const SA_CTL_PKEY_HOLD_TIME = 0x03050028 + +const SA_CTL_PKEY_MOVE_VELOCITY = 0x03050029 + +const SA_CTL_PKEY_MOVE_ACCELERATION = 0x0305002b + +const SA_CTL_PKEY_MAX_CL_FREQUENCY = 0x0305002f + +const SA_CTL_PKEY_DEFAULT_MAX_CL_FREQUENCY = 0x03050057 + +const SA_CTL_PKEY_STEP_FREQUENCY = 0x0305002e + +const SA_CTL_PKEY_STEP_AMPLITUDE = 0x03050030 + +const SA_CTL_PKEY_FOLLOWING_ERROR_LIMIT = 0x03050055 + +const SA_CTL_PKEY_FOLLOWING_ERROR = 0x03020055 + +const SA_CTL_PKEY_FOLLOWING_ERROR_MAX = 0x05020055 + +const SA_CTL_PKEY_BROADCAST_STOP_OPTIONS = 0x0305005d + +const SA_CTL_PKEY_SENSOR_POWER_MODE = 0x03080019 + +const SA_CTL_PKEY_SENSOR_POWER_SAVE_DELAY = 0x03080054 + +const SA_CTL_PKEY_POSITION_MEAN_SHIFT = 0x03090022 + +const SA_CTL_PKEY_SAFE_DIRECTION = 0x03090027 + +const SA_CTL_PKEY_CL_INPUT_SENSOR_VALUE = 0x0302001d + +const SA_CTL_PKEY_CL_INPUT_AUX_VALUE = 0x030200b2 + +const SA_CTL_PKEY_TARGET_TO_ZERO_VOLTAGE_HOLD_TH = 0x030200b9 + +const SA_CTL_PKEY_HOLDING_GAIN_REDUCTION = 0x0302004e + +const SA_CTL_PKEY_CH_EMERGENCY_STOP_MODE = 0x02020088 + +const SA_CTL_PKEY_IN_POSITION_THRESHOLD = 0x03050058 + +const SA_CTL_PKEY_IN_POSITION_DELAY = 0x03050054 + +const SA_CTL_PKEY_MOTOR_LOAD_PROTECTION_THRESHOLD = 0x03020115 + +const SA_CTL_PKEY_BRAKE_OFF_DELAY = 0x03050117 + +const SA_CTL_PKEY_BRAKE_ON_DELAY = 0x03050118 + +const SA_CTL_PKEY_RESONANCE_FREQUENCY_1 = 0x030900e0 + +const SA_CTL_PKEY_RESONANCE_FREQUENCY_2 = 0x030900e1 + +const SA_CTL_PKEY_SCAN_VALUE_MIN = 0x03050020 + +const SA_CTL_PKEY_SCAN_VALUE_MAX = 0x03050021 + +const SA_CTL_PKEY_SCAN_VALUE_NEUTRAL = 0x030500a0 + +const SA_CTL_PKEY_POSITION_VALUE_MIN = 0x030500e7 + +const SA_CTL_PKEY_POSITION_VALUE_MAX = 0x030500e8 + +const SA_CTL_PKEY_MOVE_TRIGGER_SELECT = 0x030200eb + +const SA_CTL_PKEY_CH_EVENT_NOTIFICATION_OPTIONS = 0x0310005d + +const SA_CTL_PKEY_FILTER_FREQUENCY_1 = 0x030900e0 + +const SA_CTL_PKEY_FILTER_FREQUENCY_2 = 0x030900e1 + +const SA_CTL_PKEY_FILTER_GAIN_1 = 0x030900ed + +const SA_CTL_PKEY_FILTER_GAIN_2 = 0x030900ee + +const SA_CTL_PKEY_FILTER_QFACTOR_1 = 0x030900ef + +const SA_CTL_PKEY_FILTER_QFACTOR_2 = 0x030900f0 + +const SA_CTL_PKEY_FILTER_TYPE_1 = 0x030900f1 + +const SA_CTL_PKEY_FILTER_TYPE_2 = 0x030900f2 + +const SA_CTL_PKEY_LOGICAL_SCALE_OFFSET = 0x02040024 + +const SA_CTL_PKEY_LOGICAL_SCALE_INVERSION = 0x02040025 + +const SA_CTL_PKEY_RANGE_LIMIT_MIN = 0x02040020 + +const SA_CTL_PKEY_RANGE_LIMIT_MAX = 0x02040021 + +const SA_CTL_PKEY_DEFAULT_RANGE_LIMIT_MIN = 0x020400c0 + +const SA_CTL_PKEY_DEFAULT_RANGE_LIMIT_MAX = 0x020400c1 + +const SA_CTL_PKEY_CALIBRATION_OPTIONS = 0x0306005d + +const SA_CTL_PKEY_SIGNAL_CORRECTION_OPTIONS = 0x0306001c + +const SA_CTL_PKEY_SCAN_RANGE = 0x030600a0 + +const SA_CTL_PKEY_REFERENCING_OPTIONS = 0x0307005d + +const SA_CTL_PKEY_DIST_CODE_INVERTED = 0x0307000e + +const SA_CTL_PKEY_DISTANCE_TO_REF_MARK = 0x030700a2 + +const SA_CTL_PKEY_POS_MOVEMENT_TYPE = 0x0309003f + +const SA_CTL_PKEY_POS_IS_CUSTOM_TYPE = 0x03090041 + +const SA_CTL_PKEY_POS_BASE_UNIT = 0x03090042 + +const SA_CTL_PKEY_POS_BASE_RESOLUTION = 0x03090043 + +const SA_CTL_PKEY_POS_HEAD_TYPE = 0x0309008e + +const SA_CTL_PKEY_POS_REF_TYPE = 0x03090048 + +const SA_CTL_PKEY_POS_P_GAIN = 0x0309004b + +const SA_CTL_PKEY_POS_I_GAIN = 0x0309004c + +const SA_CTL_PKEY_POS_D_GAIN = 0x0309004d + +const SA_CTL_PKEY_POS_PID_SHIFT = 0x0309004e + +const SA_CTL_PKEY_POS_ANTI_WINDUP = 0x0309004f + +const SA_CTL_PKEY_POS_I_GAIN2 = 0x03090097 + +const SA_CTL_PKEY_POS_FOLLOWING_ERROR_TH = 0x03090098 + +const SA_CTL_PKEY_POS_ESD_DIST_TH = 0x03090050 + +const SA_CTL_PKEY_POS_ESD_COUNTER_TH = 0x03090051 + +const SA_CTL_PKEY_POS_TARGET_REACHED_TH = 0x03090052 + +const SA_CTL_PKEY_POS_TARGET_HOLD_TH = 0x03090053 + +const SA_CTL_PKEY_POS_CL_TYPE = 0x0309005d + +const SA_CTL_PKEY_POS_ADV_CL_KP = 0x03090097 + +const SA_CTL_PKEY_POS_ADV_CL_KD = 0x03090098 + +const SA_CTL_PKEY_POS_ADV_CL_SHIFT = 0x0309009a + +const SA_CTL_PKEY_POS_ADV_CL_DELAY = 0x0309009b + +const SA_CTL_PKEY_POS_ADV_CL_ALPHA = 0x0309009c + +const SA_CTL_PKEY_POS_ADV_CL_BETA = 0x0309009d + +const SA_CTL_PKEY_POS_ADV_CL_GAMMA = 0x0309009e + +const SA_CTL_PKEY_POS_ADV_CL_B0_SHIFT = 0x0309009f + +const SA_CTL_PKEY_POS_ADV_CL_B0 = 0x030900a0 + +const SA_CTL_PKEY_POS_SAVE = 0x0309000a + +const SA_CTL_PKEY_POS_WRITE_PROTECTION = 0x0309000d + +const SA_CTL_PKEY_WFG_START_POSITION = 0x0d16001e + +const SA_CTL_PKEY_WFG_SIGNAL_WAVE_FORM = 0x0d16001a + +const SA_CTL_PKEY_WFG_SIGNAL_PERIOD = 0x0d1600e2 + +const SA_CTL_PKEY_WFG_SIGNAL_DELAY = 0x0d1600e3 + +const SA_CTL_PKEY_WFG_SIGNAL_SYMMETRY = 0x0d1600e4 + +const SA_CTL_PKEY_WFG_SIGNAL_HOLD = 0x0d1600e5 + +const SA_CTL_PKEY_WFG_SIGNAL_NUMBER_OF_STEPS = 0x0d1600a6 + +const SA_CTL_PKEY_WFG_SIGNAL_AMPLITUDE = 0x0d160030 + +const SA_CTL_PKEY_WFG_SIGNAL_OFFSET = 0x0d1600a9 + +const SA_CTL_PKEY_WFG_SIGNAL_BUFFER_DATA = 0x0d160008 + +const SA_CTL_PKEY_WFG_SIGNAL_BUFFER_SIZE = 0x0d160086 + +const SA_CTL_PKEY_WFG_AMP_MOD_WAVE_FORM = 0x0d17001a + +const SA_CTL_PKEY_WFG_AMP_MOD_PERIOD = 0x0d1700e2 + +const SA_CTL_PKEY_WFG_AMP_MOD_SYMMETRY = 0x0d1700e4 + +const SA_CTL_PKEY_WFG_AMP_MOD_HOLD = 0x0d1700e5 + +const SA_CTL_PKEY_WFG_AMP_MOD_NUMBER_OF_STEPS = 0x0d1700a6 + +const SA_CTL_PKEY_WFG_AMP_MOD_BUFFER_DATA = 0x0d170008 + +const SA_CTL_PKEY_WFG_AMP_MOD_BUFFER_SIZE = 0x0d170086 + +const SA_CTL_PKEY_WFG_FREQ_MOD_WAVE_FORM = 0x0d18001a + +const SA_CTL_PKEY_WFG_FREQ_MOD_PERIOD = 0x0d1800e2 + +const SA_CTL_PKEY_WFG_FREQ_MOD_SYMMETRY = 0x0d1800e4 + +const SA_CTL_PKEY_WFG_FREQ_MOD_HOLD = 0x0d1800e5 + +const SA_CTL_PKEY_WFG_FREQ_MOD_NUMBER_OF_STEPS = 0x0d1800a6 + +const SA_CTL_PKEY_WFG_FREQ_MOD_BUFFER_DATA = 0x0d180008 + +const SA_CTL_PKEY_WFG_FREQ_MOD_BUFFER_SIZE = 0x0d180086 + +const SA_CTL_PKEY_ALIGN_FLS_INTENSITY = 0x10030086 + +const SA_CTL_PKEY_ALIGN_MODE = 0x10030087 + +const SA_CTL_PKEY_ALIGN_SAMPLE_MODE = 0x1003001a + +const SA_CTL_PKEY_ALIGN_INPUT_SELECT = 0x10030018 + +const SA_CTL_PKEY_ALIGN_MAX_ITERATIONS = 0x10030126 + +const SA_CTL_PKEY_ALIGN_SAMPLE_INTENSITY_CURRENT = 0x10030123 + +const SA_CTL_PKEY_ALIGN_SAMPLE_INTENSITY_BEST = 0x10030124 + +const SA_CTL_PKEY_ALIGN_FLS_TRACKING = 0x100200b2 + +const SA_CTL_PKEY_ALIGN_FLS_POSITION = 0x100200b3 + +const SA_CTL_PKEY_ALIGN_GROW_FACTOR = 0x100200b4 + +const SA_CTL_PKEY_ALIGN_SHRINK_FACTOR = 0x100200b5 + +const SA_CTL_PKEY_ALIGN_STEP_SIZE_START = 0x10020129 + +const SA_CTL_PKEY_ALIGN_STEP_SIZE_MIN = 0x1002012a + +const SA_CTL_PKEY_ALIGN_STEP_SIZE_MAX = 0x1002012b + +const SA_CTL_PKEY_ALIGN_STEP_SIZE = 0x10020128 + +const SA_CTL_PKEY_ALIGN_SCAN_POSITION_MIN = 0x10020020 + +const SA_CTL_PKEY_ALIGN_SCAN_POSITION_MAX = 0x10020021 + +const SA_CTL_PKEY_ALIGN_OPTIONS = 0x1002005d + +const SA_CTL_PKEY_ALIGN_MIN_GRADIENT_THRESHOLD = 0x10020058 + +const SA_CTL_PKEY_ALIGN_INTENSITY_THRESHOLD = 0x100200a0 + +const SA_CTL_PKEY_ALIGN_IN_RANGE_DELAY = 0x10020054 + +const SA_CTL_PKEY_ALIGN_INTENSITY = 0x10020123 + +const SA_CTL_PKEY_ALIGN_GRADIENT = 0x10020125 + +const SA_CTL_PKEY_ALIGN_SAMPLE_SCAN_POSITION_CURRENT = 0x1002001f + +const SA_CTL_PKEY_ALIGN_SAMPLE_SCAN_POSITION_BEST = 0x10020122 + +const SA_CTL_PKEY_ALIGN_SAMPLE_POSITION_CURRENT = 0x1002001d + +const SA_CTL_PKEY_ALIGN_SAMPLE_POSITION_BEST = 0x10020121 + +const SA_CTL_PKEY_ALIGN_SIMULATOR_PEAK_POSITION = 0x10020127 + +const SA_CTL_PKEY_STREAM_BASE_RATE = 0x040f002c + +const SA_CTL_PKEY_STREAM_EXT_SYNC_RATE = 0x040f002d + +const SA_CTL_PKEY_STREAM_OPTIONS = 0x040f005d + +const SA_CTL_PKEY_STREAM_LOAD_MAX = 0x040f0301 + +const SA_CTL_PKEY_CHANNEL_ERROR = 0x0502007a + +const SA_CTL_PKEY_CHANNEL_TEMPERATURE = 0x05020034 + +const SA_CTL_PKEY_BUS_MODULE_TEMPERATURE = 0x05030034 + +const SA_CTL_PKEY_POSITIONER_FAULT_REASON = 0x05020113 + +const SA_CTL_PKEY_MOTOR_LOAD = 0x05020115 + +const SA_CTL_PKEY_MOTOR_CURRENT = 0x05020110 + +const SA_CTL_PKEY_DIAG_CLOSED_LOOP_FREQUENCY_AVG = 0x0502002e + +const SA_CTL_PKEY_DIAG_CLOSED_LOOP_FREQUENCY_MAX = 0x0502002f + +const SA_CTL_PKEY_DIAG_CLF_MEASURE_TIME_BASE = 0x050200c6 + +const SA_CTL_PKEY_IO_MODULE_OPTIONS = 0x0603005d + +const SA_CTL_PKEY_IO_MODULE_VOLTAGE = 0x06030031 + +const SA_CTL_PKEY_IO_MODULE_ANALOG_INPUT_RANGE = 0x060300a0 + +const SA_CTL_PKEY_SENSOR_MODULE_OPTIONS = 0x080b005d + +const SA_CTL_PKEY_AUX_POSITIONER_TYPE = 0x0802003c + +const SA_CTL_PKEY_AUX_POSITIONER_TYPE_NAME = 0x0802003d + +const SA_CTL_PKEY_AUX_INPUT_SELECT = 0x08020018 + +const SA_CTL_PKEY_AUX_IO_MODULE_INPUT_INDEX = 0x081100aa + +const SA_CTL_PKEY_AUX_SENSOR_MODULE_INPUT_INDEX = 0x080b00aa + +const SA_CTL_PKEY_AUX_IO_MODULE_INPUT0_VALUE = 0x08110000 + +const SA_CTL_PKEY_AUX_IO_MODULE_INPUT1_VALUE = 0x08110001 + +const SA_CTL_PKEY_AUX_SENSOR_MODULE_INPUT0_VALUE = 0x080b0000 + +const SA_CTL_PKEY_AUX_SENSOR_MODULE_INPUT1_VALUE = 0x080b0001 + +const SA_CTL_PKEY_AUX_DIRECTION_INVERSION = 0x0809000e + +const SA_CTL_PKEY_AUX_DIGITAL_INPUT_VALUE = 0x080300ad + +const SA_CTL_PKEY_AUX_SM_DIGITAL_INPUT_VALUE = 0x080b00ad + +const SA_CTL_PKEY_AUX_DIGITAL_OUTPUT_VALUE = 0x080300ae + +const SA_CTL_PKEY_AUX_DIGITAL_OUTPUT_SET = 0x080300b0 + +const SA_CTL_PKEY_AUX_DIGITAL_OUTPUT_CLEAR = 0x080300b1 + +const SA_CTL_PKEY_AUX_ANALOG_OUTPUT_VALUE0 = 0x08030000 + +const SA_CTL_PKEY_AUX_ANALOG_OUTPUT_VALUE1 = 0x08030001 + +const SA_CTL_PKEY_AUX_CORRECTION_MAX = 0x080200d8 + +const SA_CTL_PKEY_THD_INPUT_SELECT = 0x09020018 + +const SA_CTL_PKEY_THD_IO_MODULE_INPUT_INDEX = 0x091100aa + +const SA_CTL_PKEY_THD_SENSOR_MODULE_INPUT_INDEX = 0x090b00aa + +const SA_CTL_PKEY_THD_THRESHOLD_HIGH = 0x090200b4 + +const SA_CTL_PKEY_THD_THRESHOLD_LOW = 0x090200b5 + +const SA_CTL_PKEY_THD_INVERSION = 0x0902000e + +const SA_CTL_PKEY_DEV_INPUT_TRIG_SELECT = 0x060d009d + +const SA_CTL_PKEY_DEV_INPUT_TRIG_MODE = 0x060d0087 + +const SA_CTL_PKEY_DEV_INPUT_TRIG_CONDITION = 0x060d005a + +const SA_CTL_PKEY_DEV_INPUT_TRIG_DEBOUNCE = 0x060d0058 + +const SA_CTL_PKEY_CH_INPUT_TRIG_SELECT = 0x0615009d + +const SA_CTL_PKEY_CH_INPUT_TRIG_MODE = 0x06150087 + +const SA_CTL_PKEY_CH_INPUT_TRIG_CONDITION = 0x0615005a + +const SA_CTL_PKEY_CH_OUTPUT_TRIG_MODE = 0x060e0087 + +const SA_CTL_PKEY_CH_OUTPUT_TRIG_POLARITY = 0x060e005b + +const SA_CTL_PKEY_CH_OUTPUT_TRIG_PULSE_WIDTH = 0x060e005c + +const SA_CTL_PKEY_CH_POS_COMP_START_THRESHOLD = 0x060e0058 + +const SA_CTL_PKEY_CH_POS_COMP_INCREMENT = 0x060e0059 + +const SA_CTL_PKEY_CH_POS_COMP_DIRECTION = 0x060e0026 + +const SA_CTL_PKEY_CH_POS_COMP_LIMIT_MIN = 0x060e0020 + +const SA_CTL_PKEY_CH_POS_COMP_LIMIT_MAX = 0x060e0021 + +const SA_CTL_PKEY_CH_POS_COMP_HYSTERESIS = 0x060e00e6 + +const SA_CTL_PKEY_CAPTURE_BUFFER_ACTIVE = 0x0b030019 + +const SA_CTL_PKEY_CAPTURE_BUFFER_RATE = 0x0b03002c + +const SA_CTL_PKEY_CAPTURE_BUFFER_TRIGGER_MODE = 0x0b0300c4 + +const SA_CTL_PKEY_CAPTURE_BUFFER_DATASET_TYPE = 0x0b030117 + +const SA_CTL_PKEY_CAPTURE_BUFFER_POSITION_TYPE = 0x0b030118 + +const SA_CTL_PKEY_CAPTURE_BUFFER_POSITION_INDEX = 0x0b030119 + +const SA_CTL_PKEY_CAPTURE_BUFFER_AUX_INPUT_INDEX = 0x0b030120 + +const SA_CTL_PKEY_CAPTURE_BUFFER_SIZE = 0x0b030086 + +const SA_CTL_PKEY_CAPTURE_BUFFER_DATA = 0x0b030008 + +const SA_CTL_PKEY_TACTILE_SENSING_MODE = 0x0f020087 + +const SA_CTL_PKEY_TACTILE_SENSING_TIMEBASE = 0x0f0200c6 + +const SA_CTL_PKEY_TACTILE_SENSING_DURATION = 0x0f0200ec + +const SA_CTL_PKEY_TACTILE_SENSING_DEADTIME = 0x0f020028 + +const SA_CTL_PKEY_TACTILE_SENSING_VALUE_THRESHOLD = 0x0f020058 + +const SA_CTL_PKEY_TACTILE_SENSING_VALUE = 0x0f020000 + +const SA_CTL_PKEY_TACTILE_SENSING_VALUE_MAX = 0x0f020021 + +const SA_CTL_PKEY_TACTILE_SENSING_LEVEL_THRESHOLD = 0x0f02002c + +const SA_CTL_PKEY_TACTILE_SENSING_LEVEL = 0x0f02002d + +const SA_CTL_PKEY_TACTILE_SENSING_LEVEL_MAX = 0x0f02002e + +const SA_CTL_PKEY_TACTILE_SENSING_LEVEL_BASE_FILTER = 0x0f0200a5 + +const SA_CTL_PKEY_TACTILE_SENSING_CAPTURE_POSITION = 0x0f020011 + +const SA_CTL_PKEY_HM_STATE = 0x020c000f + +const SA_CTL_PKEY_HM_LOCK_OPTIONS = 0x020c0083 + +const SA_CTL_PKEY_HM_DEFAULT_LOCK_OPTIONS = 0x020c0084 + +const SA_CTL_PKEY_API_EVENT_NOTIFICATION_OPTIONS = 0xf010005d + +const SA_CTL_PKEY_EVENT_NOTIFICATION_OPTIONS = 0xf010005d + +const SA_CTL_PKEY_API_AUTO_RECONNECT = 0xf01000a1 + +const SA_CTL_PKEY_AUTO_RECONNECT = 0xf01000a1 + +const SA_CTL_PKEY_API_LOCATOR = 0xf010003d + +const SA_CTL_DEV_STATE_BIT_HM_PRESENT = 0x00000001 + +const SA_CTL_DEV_STATE_BIT_MOVEMENT_LOCKED = 0x00000002 + +const SA_CTL_DEV_STATE_BIT_AMPLIFIER_LOCKED = 0x00000004 + +const SA_CTL_DEV_STATE_BIT_IO_MODULE_INPUT = 0x00000008 + +const SA_CTL_DEV_STATE_BIT_GLOBAL_INPUT = 0x00000010 + +const SA_CTL_DEV_STATE_BIT_INTERNAL_COMM_FAILURE = 0x00000100 + +const SA_CTL_DEV_STATE_BIT_IS_STREAMING = 0x00001000 + +const SA_CTL_DEV_STATE_BIT_EEPROM_BUSY = 0x00010000 + +const SA_CTL_MOD_STATE_BIT_SM_PRESENT = 0x00000001 + +const SA_CTL_MOD_STATE_BIT_BOOSTER_PRESENT = 0x00000002 + +const SA_CTL_MOD_STATE_BIT_ADJUSTMENT_ACTIVE = 0x00000004 + +const SA_CTL_MOD_STATE_BIT_IOM_PRESENT = 0x00000008 + +const SA_CTL_MOD_STATE_BIT_CAPTURE_BUFFER_ACTIVE = 0x00000010 + +const SA_CTL_MOD_STATE_BIT_CAPTURE_BUFFER_TRIGGERED = 0x00000020 + +const SA_CTL_MOD_STATE_BIT_ALIGNMENT_ACTIVE = 0x00000040 + +const SA_CTL_MOD_STATE_BIT_ALIGNMENT_IN_RANGE = 0x00000080 + +const SA_CTL_MOD_STATE_BIT_INTERNAL_COMM_FAILURE = 0x00000100 + +const SA_CTL_MOD_STATE_BIT_FAN_FAILURE = 0x00000800 + +const SA_CTL_MOD_STATE_BIT_POWER_SUPPLY_FAILURE = 0x00001000 + +const SA_CTL_MOD_STATE_BIT_HIGH_VOLTAGE_FAILURE = 0x00001000 + +const SA_CTL_MOD_STATE_BIT_POWER_SUPPLY_OVERLOAD = 0x00002000 + +const SA_CTL_MOD_STATE_BIT_HIGH_VOLTAGE_OVERLOAD = 0x00002000 + +const SA_CTL_MOD_STATE_BIT_OVER_TEMPERATURE = 0x00004000 + +const SA_CTL_MOD_STATE_BIT_EEPROM_BUSY = 0x00010000 + +const SA_CTL_CH_STATE_BIT_ACTIVELY_MOVING = 0x00000001 + +const SA_CTL_CH_STATE_BIT_CLOSED_LOOP_ACTIVE = 0x00000002 + +const SA_CTL_CH_STATE_BIT_CALIBRATING = 0x00000004 + +const SA_CTL_CH_STATE_BIT_REFERENCING = 0x00000008 + +const SA_CTL_CH_STATE_BIT_MOVE_DELAYED = 0x00000010 + +const SA_CTL_CH_STATE_BIT_SENSOR_PRESENT = 0x00000020 + +const SA_CTL_CH_STATE_BIT_IS_CALIBRATED = 0x00000040 + +const SA_CTL_CH_STATE_BIT_IS_REFERENCED = 0x00000080 + +const SA_CTL_CH_STATE_BIT_END_STOP_REACHED = 0x00000100 + +const SA_CTL_CH_STATE_BIT_RANGE_LIMIT_REACHED = 0x00000200 + +const SA_CTL_CH_STATE_BIT_FOLLOWING_LIMIT_REACHED = 0x00000400 + +const SA_CTL_CH_STATE_BIT_MOVEMENT_FAILED = 0x00000800 + +const SA_CTL_CH_STATE_BIT_IS_STREAMING = 0x00001000 + +const SA_CTL_CH_STATE_BIT_POSITIONER_OVERLOAD = 0x00002000 + +const SA_CTL_CH_STATE_BIT_OVER_TEMPERATURE = 0x00004000 + +const SA_CTL_CH_STATE_BIT_REFERENCE_MARK = 0x00008000 + +const SA_CTL_CH_STATE_BIT_IS_PHASED = 0x00010000 + +const SA_CTL_CH_STATE_BIT_POSITIONER_FAULT = 0x00020000 + +const SA_CTL_CH_STATE_BIT_AMPLIFIER_ENABLED = 0x00040000 + +const SA_CTL_CH_STATE_BIT_IN_POSITION = 0x00080000 + +const SA_CTL_CH_STATE_BIT_BRAKE_ENABLED = 0x00100000 + +const SA_CTL_CH_STATE_BIT_TACTILE_SENSING_TRIGGERED = 0x00200000 + +const SA_CTL_HM_STATE_BIT_INTERNAL_COMM_FAILURE = 0x00000100 + +const SA_CTL_HM_STATE_BIT_IS_INTERNAL = 0x00000200 + +const SA_CTL_HM_STATE_BIT_EEPROM_BUSY = 0x00010000 + +const SA_CTL_MOVE_MODE_CL_ABSOLUTE = 0 + +const SA_CTL_MOVE_MODE_CL_RELATIVE = 1 + +const SA_CTL_MOVE_MODE_SCAN_ABSOLUTE = 2 + +const SA_CTL_MOVE_MODE_SCAN_RELATIVE = 3 + +const SA_CTL_MOVE_MODE_STEP = 4 + +const SA_CTL_MOVE_MODE_CL_WFG = 5 + +const SA_CTL_MOVE_MODE_OL_WFG = 6 + +const SA_CTL_ACTUATOR_MODE_NORMAL = 0 + +const SA_CTL_ACTUATOR_MODE_QUIET = 1 + +const SA_CTL_ACTUATOR_MODE_LOW_VIBRATION = 2 + +const SA_CTL_CONTROL_LOOP_INPUT_DISABLED = 0 + +const SA_CTL_CONTROL_LOOP_INPUT_SENSOR = 1 + +const SA_CTL_CONTROL_LOOP_INPUT_POSITION = 1 + +const SA_CTL_CONTROL_LOOP_INPUT_AUX_IN = 2 + +const SA_CTL_CONTROL_LOOP_INPUT_MODULE_LINK = 3 + +const SA_CTL_MOVE_TRIGGER_SELECT_DIRECT = 0 + +const SA_CTL_MOVE_TRIGGER_SELECT_TACTILE_SENSING = 1 + +const SA_CTL_TACTILE_SENSING_MODE_SINGLE_SHOT = 0 + +const SA_CTL_TACTILE_SENSING_MODE_CONTINUOUS = 1 + +const SA_CTL_SENSOR_INPUT_SELECT_POSITION = 0 + +const SA_CTL_SENSOR_INPUT_SELECT_CALC_SYS = 1 + +const SA_CTL_SENSOR_INPUT_SELECT_POS_PLUS_AUX_IN = 2 + +const SA_CTL_AUX_INPUT_SELECT_IO_MODULE = 0 + +const SA_CTL_AUX_INPUT_SELECT_SENSOR_MODULE = 1 + +const SA_CTL_IO_DIGITAL_INPUT_BIT_GP_IN_1 = 0x00000001 + +const SA_CTL_IO_DIGITAL_INPUT_BIT_GP_IN_2 = 0x00000002 + +const SA_CTL_IO_DIGITAL_INPUT_BIT_GP_IN_3 = 0x00000004 + +const SA_CTL_IO_DIGITAL_INPUT_BIT_GP_IN_4 = 0x00000008 + +const SA_CTL_IO_DIGITAL_OUTPUT_BIT_GP_OUT_1 = 0x00000001 + +const SA_CTL_IO_DIGITAL_OUTPUT_BIT_GP_OUT_2 = 0x00000002 + +const SA_CTL_IO_DIGITAL_OUTPUT_BIT_GP_OUT_3 = 0x00000004 + +const SA_CTL_IO_DIGITAL_OUTPUT_BIT_GP_OUT_4 = 0x00000008 + +const SA_CTL_SM_DIGITAL_INPUT_BIT_POWER_SUPPLY = 0x00000001 + +const SA_CTL_SM_DIGITAL_INPUT_BIT_PRESSURE_SENSOR = 0x00000002 + +const SA_CTL_SM_DIGITAL_INPUT_BIT_ES_1 = 0x00000004 + +const SA_CTL_SM_DIGITAL_INPUT_BIT_ES_2 = 0x00000008 + +const SA_CTL_SM_DIGITAL_INPUT_BIT_GP_IN_1 = 0x00000010 + +const SA_CTL_SM_DIGITAL_INPUT_BIT_GP_IN_2 = 0x00000020 + +const SA_CTL_SM_DIGITAL_INPUT_BIT_GP_IN_3 = 0x00000040 + +const SA_CTL_SM_DIGITAL_INPUT_BIT_SYNC = 0x00000080 + +const SA_CTL_THD_INPUT_SELECT_IO_MODULE = 0 + +const SA_CTL_THD_INPUT_SELECT_SENSOR_MODULE = 1 + +const SA_CTL_EMERGENCY_STOP_MODE_NORMAL = 0 + +const SA_CTL_EMERGENCY_STOP_MODE_RESTRICTED = 1 + +const SA_CTL_EMERGENCY_STOP_MODE_AUTO_RELEASE = 2 + +const SA_CTL_CMD_GROUP_TRIGGER_MODE_DIRECT = 0 + +const SA_CTL_CMD_GROUP_TRIGGER_MODE_EXTERNAL = 1 + +const SA_CTL_STREAM_TRIGGER_MODE_DIRECT = 0 + +const SA_CTL_STREAM_TRIGGER_MODE_EXTERNAL_ONCE = 1 + +const SA_CTL_STREAM_TRIGGER_MODE_EXTERNAL_SYNC = 2 + +const SA_CTL_STREAM_TRIGGER_MODE_EXTERNAL = 3 + +const SA_CTL_STOPEXT_OPT_BIT_HARD_STOP = 0x00000001 + +const SA_CTL_STOPEXT_OPT_BIT_SOFT_STOP = 0x00000002 + +const SA_CTL_STOPEXT_OPT_BIT_HOLDING = 0x00000004 + +const SA_CTL_STREAM_OPT_BIT_INTERPOLATION_DIS = 0x00000001 + +const SA_CTL_STARTUP_OPT_BIT_AMPLIFIER_ENABLE = 0x00000001 + +const SA_CTL_POS_CTRL_OPT_BIT_ACC_REL_POS_DIS = 0x00000001 + +const SA_CTL_POS_CTRL_OPT_BIT_NO_SLIP = 0x00000002 + +const SA_CTL_POS_CTRL_OPT_BIT_NO_SLIP_WHILE_HOLDING = 0x00000004 + +const SA_CTL_POS_CTRL_OPT_BIT_FORCED_SLIP_DIS = 0x00000008 + +const SA_CTL_POS_CTRL_OPT_BIT_STOP_ON_FOLLOWING_ERR = 0x00000010 + +const SA_CTL_POS_CTRL_OPT_BIT_TARGET_TO_ZERO_VOLTAGE = 0x00000020 + +const SA_CTL_POS_CTRL_OPT_BIT_CL_DIS_ON_FOLLOWING_ERR = 0x00000040 + +const SA_CTL_POS_CTRL_OPT_BIT_CL_DIS_ON_EMERGENCY_STOP = 0x00000080 + +const SA_CTL_POS_CTRL_OPT_BIT_IN_POSITION = 0x00000100 + +const SA_CTL_POS_CTRL_OPT_BIT_COUPLED_BRAKE_CONTROL = 0x00000200 + +const SA_CTL_POS_CTRL_OPT_BIT_WFG_MOVE_TO_START = 0x00000400 + +const SA_CTL_POS_CTRL_OPT_BIT_STOP_ON_TACTILE_SENSING = 0x00000800 + +const SA_CTL_CALIB_OPT_BIT_DIRECTION = 0x00000001 + +const SA_CTL_CALIB_OPT_BIT_DIST_CODE_INV_DETECT = 0x00000002 + +const SA_CTL_CALIB_OPT_BIT_ASC_CALIBRATION = 0x00000004 + +const SA_CTL_CALIB_OPT_BIT_REF_MARK_TEST = 0x00000008 + +const SA_CTL_CALIB_OPT_BIT_LIMITED_TRAVEL_RANGE = 0x00000100 + +const SA_CTL_CALIB_OPT_BIT_INVALIDATE = 0x01000000 + +const SA_CTL_REF_OPT_BIT_START_DIR = 0x00000001 + +const SA_CTL_REF_OPT_BIT_REVERSE_DIR = 0x00000002 + +const SA_CTL_REF_OPT_BIT_AUTO_ZERO = 0x00000004 + +const SA_CTL_REF_OPT_BIT_ABORT_ON_ENDSTOP = 0x00000008 + +const SA_CTL_REF_OPT_BIT_CONTINUE_ON_REF_FOUND = 0x00000010 + +const SA_CTL_REF_OPT_BIT_STOP_ON_REF_FOUND = 0x00000020 + +const SA_CTL_REF_OPT_BIT_INVALIDATE = 0x01000000 + +const SA_CTL_SENSOR_MODE_DISABLED = 0 + +const SA_CTL_SENSOR_MODE_ENABLED = 1 + +const SA_CTL_SENSOR_MODE_POWER_SAVE = 2 + +const SA_CTL_STOP_OPT_BIT_END_STOP_REACHED = 0x00000001 + +const SA_CTL_STOP_OPT_BIT_RANGE_LIMIT_REACHED = 0x00000002 + +const SA_CTL_STOP_OPT_BIT_FOLLOWING_LIMIT_REACHED = 0x00000004 + +const SA_CTL_STOP_OPT_BIT_POSITIONER_OVERLOAD = 0x00000008 + +const SA_CTL_STOP_OPT_BIT_TACTILE_SENSING = 0x00000010 + +const SA_CTL_AMP_MODE_DEFAULT = 0 + +const SA_CTL_AMP_MODE_POSITIONER_INTERLOCK = 1 + +const SA_CTL_WFG_WAVE_FORM_CONST = 0 + +const SA_CTL_WFG_WAVE_FORM_SAWTOOTH = 1 + +const SA_CTL_WFG_WAVE_FORM_STAIRCASE = 2 + +const SA_CTL_WFG_WAVE_FORM_SINE = 3 + +const SA_CTL_WFG_WAVE_FORM_CLV_OUTWARD = 4 + +const SA_CTL_WFG_WAVE_FORM_CLV_INWARD = 5 + +const SA_CTL_WFG_WAVE_FORM_USER = 6 + +const SA_CTL_DEV_INPUT_TRIG_SELECT_IO_MODULE = 0 + +const SA_CTL_DEV_INPUT_TRIG_SELECT_GLOBAL_INPUT = 1 + +const SA_CTL_DEV_INPUT_TRIG_MODE_DISABLED = 0 + +const SA_CTL_DEV_INPUT_TRIG_MODE_EMERGENCY_STOP = 1 + +const SA_CTL_DEV_INPUT_TRIG_MODE_STREAM = 2 + +const SA_CTL_DEV_INPUT_TRIG_MODE_CMD_GROUP = 3 + +const SA_CTL_DEV_INPUT_TRIG_MODE_EVENT = 4 + +const SA_CTL_DEV_INPUT_TRIG_MODE_AMPLIFIER_LOCK = 5 + +const SA_CTL_CH_INPUT_TRIG_SELECT_IO_MODULE = 0 + +const SA_CTL_CH_INPUT_TRIG_SELECT_SENSOR_MODULE = 1 + +const SA_CTL_CH_INPUT_TRIG_MODE_DISABLED = 0 + +const SA_CTL_CH_INPUT_TRIG_MODE_EMERGENCY_STOP = 1 + +const SA_CTL_CH_INPUT_TRIG_MODE_STOP_TRIGGER = 2 + +const SA_CTL_CH_OUTPUT_TRIG_MODE_CONSTANT = 0 + +const SA_CTL_CH_OUTPUT_TRIG_MODE_POSITION_COMPARE = 1 + +const SA_CTL_CH_OUTPUT_TRIG_MODE_TARGET_REACHED = 2 + +const SA_CTL_CH_OUTPUT_TRIG_MODE_ACTIVELY_MOVING = 3 + +const SA_CTL_CH_OUTPUT_TRIG_MODE_IN_POSITION = 4 + +const SA_CTL_CH_OUTPUT_TRIG_MODE_IN_RANGE = 6 + +const SA_CTL_CH_OUTPUT_TRIG_MODE_ALIGN_IN_RANGE = 7 + +const SA_CTL_TRIGGER_CONDITION_RISING = 0 + +const SA_CTL_TRIGGER_CONDITION_FALLING = 1 + +const SA_CTL_TRIGGER_CONDITION_EITHER = 2 + +const SA_CTL_TRIGGER_POLARITY_ACTIVE_LOW = 0 + +const SA_CTL_TRIGGER_POLARITY_ACTIVE_HIGH = 1 + +const SA_CTL_CAPTURE_BUFFER_INACTIVE = 0 + +const SA_CTL_CAPTURE_BUFFER_ACTIVE = 1 + +const SA_CTL_CAPTURE_BUFFER_TRIGGER_MODE_DIRECT = 0 + +const SA_CTL_CAPTURE_BUFFER_DATASET_TYPE_0 = 0 + +const SA_CTL_CAPTURE_BUFFER_DATASET_TYPE_1 = 1 + +const SA_CTL_CAPTURE_BUFFER_DATASET_TYPE_2 = 2 + +const SA_CTL_CAPTURE_BUFFER_DATASET_TYPE_3 = 3 + +const SA_CTL_CAPTURE_BUFFER_POS_TYPE_CURRENT_POS = 0 + +const SA_CTL_CAPTURE_BUFFER_POS_TYPE_TARGET_POS = 1 + +const SA_CTL_CAPTURE_BUFFER_STATE_BIT_ACTIVE = 0x00000001 + +const SA_CTL_CAPTURE_BUFFER_STATE_BIT_TRIGGERED = 0x00000002 + +const SA_CTL_ALIGNMENT_FLS_TRACKING_DISABLED = 0 + +const SA_CTL_ALIGNMENT_FLS_TRACKING_ENABLED = 1 + +const SA_CTL_ALIGNMENT_DISABLED = 0 + +const SA_CTL_ALIGNMENT_MODE_1 = 1 + +const SA_CTL_ALIGNMENT_MODE_2 = 2 + +const SA_CTL_ALIGN_SAMPLE_MODE_HIGHEST = 0 + +const SA_CTL_ALIGN_SAMPLE_MODE_LOWEST = 1 + +const SA_CTL_ALIGN_INPUT_SELECT_AIN_1 = 0 + +const SA_CTL_ALIGN_INPUT_SELECT_AIN_2 = 1 + +const SA_CTL_ALIGN_INPUT_SELECT_AIN_3 = 2 + +const SA_CTL_ALIGN_INPUT_SELECT_AIN_4 = 3 + +const SA_CTL_ALIGN_INPUT_SELECT_AIN_5 = 4 + +const SA_CTL_ALIGN_INPUT_SELECT_AIN_6 = 5 + +const SA_CTL_ALIGN_INPUT_SELECT_SIMULATOR = 6 + +const SA_CTL_ALIGN_OPT_BIT_INVERSION = 0x00000001 + +const SA_CTL_HM1_LOCK_OPT_BIT_GLOBAL = 0x00000001 + +const SA_CTL_HM1_LOCK_OPT_BIT_CONTROL = 0x00000002 + +const SA_CTL_HM1_LOCK_OPT_BIT_CHANNEL_MENU = 0x00000010 + +const SA_CTL_HM1_LOCK_OPT_BIT_GROUP_MENU = 0x00000020 + +const SA_CTL_HM1_LOCK_OPT_BIT_SETTINGS_MENU = 0x00000040 + +const SA_CTL_HM1_LOCK_OPT_BIT_LOAD_CFG_MENU = 0x00000080 + +const SA_CTL_HM1_LOCK_OPT_BIT_SAVE_CFG_MENU = 0x00000100 + +const SA_CTL_HM1_LOCK_OPT_BIT_CTRL_MODE_PARAM_MENU = 0x00000200 + +const SA_CTL_HM1_LOCK_OPT_BIT_CHANNEL_NAME = 0x00001000 + +const SA_CTL_HM1_LOCK_OPT_BIT_POS_TYPE = 0x00002000 + +const SA_CTL_HM1_LOCK_OPT_BIT_SAFE_DIR = 0x00004000 + +const SA_CTL_HM1_LOCK_OPT_BIT_CALIBRATE = 0x00008000 + +const SA_CTL_HM1_LOCK_OPT_BIT_REFERENCE = 0x00010000 + +const SA_CTL_HM1_LOCK_OPT_BIT_SET_POSITION = 0x00020000 + +const SA_CTL_HM1_LOCK_OPT_BIT_MAX_CLF = 0x00040000 + +const SA_CTL_HM1_LOCK_OPT_BIT_POWER_MODE = 0x00080000 + +const SA_CTL_HM1_LOCK_OPT_BIT_ACTUATOR_MODE = 0x00100000 + +const SA_CTL_HM1_LOCK_OPT_BIT_RANGE_LIMIT = 0x00200000 + +const SA_CTL_HM1_LOCK_OPT_BIT_CONTROL_LOOP_INPUT = 0x00400000 + +const SA_CTL_HM1_LOCK_OPT_BIT_POS_CTRL_OPT = 0x00800000 + +const SA_CTL_HM1_LOCK_OPT_BIT_RESONANCE_FREQ = 0x01000000 + +const SA_CTL_EVT_OPT_BIT_REQUEST_READY_ENABLED = 0x00000001 + +const SA_CTL_EVT_OPT_BIT_MOVE_OVERRIDDEN_ENABLED = 0x00000010 + +const SA_CTL_POSITIONER_TYPE_MODIFIED = 0 + +const SA_CTL_POSITIONER_TYPE_AUTOMATIC = 299 + +const SA_CTL_POSITIONER_TYPE_CUSTOM0 = 250 + +const SA_CTL_POSITIONER_TYPE_CUSTOM1 = 251 + +const SA_CTL_POSITIONER_TYPE_CUSTOM2 = 252 + +const SA_CTL_POSITIONER_TYPE_CUSTOM3 = 253 + +const SA_CTL_POS_WRITE_PROTECTION_KEY = 0x534d4152 + +const SA_CTL_POS_MOVEMENT_TYPE_LINEAR = 0 + +const SA_CTL_POS_MOVEMENT_TYPE_ROTATORY = 1 + +const SA_CTL_POS_MOVEMENT_TYPE_GONIOMETER = 2 + +const SA_CTL_POS_MOVEMENT_TYPE_TIP_TILT = 3 + +const SA_CTL_POS_MOVEMENT_TYPE_IRIS = 4 + +const SA_CTL_POS_MOVEMENT_TYPE_OSCILLATOR = 5 + +const SA_CTL_POS_MOVEMENT_TYPE_HIGH_LOAD_TABLE = 6 + +const SA_CTL_IO_MODULE_VOLTAGE_3V3 = 0 + +const SA_CTL_IO_MODULE_VOLTAGE_5V = 1 + +const SA_CTL_IO_MODULE_OPT_BIT_ENABLED = 0x00000001 + +const SA_CTL_IO_MODULE_OPT_BIT_DIGITAL_OUTPUT_ENABLED = 0x00000001 + +const SA_CTL_IO_MODULE_OPT_BIT_EVENTS_ENABLED = 0x00000002 + +const SA_CTL_IO_MODULE_OPT_BIT_ANALOG_OUTPUT_ENABLED = 0x00000004 + +const SA_CTL_IO_MODULE_ANALOG_INPUT_RANGE_BI_10V = 0 + +const SA_CTL_IO_MODULE_ANALOG_INPUT_RANGE_BI_5V = 1 + +const SA_CTL_IO_MODULE_ANALOG_INPUT_RANGE_BI_2_5V = 2 + +const SA_CTL_IO_MODULE_ANALOG_INPUT_RANGE_UNI_10V = 3 + +const SA_CTL_IO_MODULE_ANALOG_INPUT_RANGE_UNI_5V = 4 + +const SA_CTL_SENSOR_MODULE_OPT_BIT_EVENTS_ENABLED = 0x00000001 + +const SA_CTL_SIGNAL_CORR_OPT_BIT_DAC = 0x00000002 + +const SA_CTL_SIGNAL_CORR_OPT_BIT_DPEC = 0x00000008 + +const SA_CTL_SIGNAL_CORR_OPT_BIT_ASC = 0x00000010 + +const SA_CTL_NETWORK_DISCOVER_MODE_DISABLED = 0 + +const SA_CTL_NETWORK_DISCOVER_MODE_PASSIVE = 1 + +const SA_CTL_NETWORK_DISCOVER_MODE_ACTIVE = 2 + +const SA_CTL_REF_TYPE_NONE = 0 + +const SA_CTL_REF_TYPE_END_STOP = 1 + +const SA_CTL_REF_TYPE_SINGLE_CODED = 2 + +const SA_CTL_REF_TYPE_DISTANCE_CODED = 3 + +const SA_CTL_REF_TYPE_ABSOLUTE = 4 + +const SA_CTL_POS_FAULT_REASON_BIT_U_PHASE_SHORT = 0x00000001 + +const SA_CTL_POS_FAULT_REASON_BIT_V_PHASE_SHORT = 0x00000002 + +const SA_CTL_POS_FAULT_REASON_BIT_W_PHASE_SHORT = 0x00000004 + +const SA_CTL_POS_FAULT_REASON_BIT_U_PHASE_OPEN = 0x00000008 + +const SA_CTL_POS_FAULT_REASON_BIT_V_PHASE_OPEN = 0x00000010 + +const SA_CTL_POS_FAULT_REASON_BIT_W_PHASE_OPEN = 0x00000020 + +const SA_CTL_POS_FAULT_REASON_BIT_CURRENT_DEVIATION = 0x00000040 + +const SA_CTL_POS_FAULT_REASON_BIT_OUTPUT_SHORT = 0x00000080 + +const SA_CTL_POS_FAULT_REASON_BIT_SENSOR_SUPPLY_SHORT = 0x00000100 + +const SA_CTL_POS_FAULT_REASON_BIT_DRIVER_FAULT = 0x00008000 + +const SA_CTL_FILTER_TYPE_NONE = 0 + +const SA_CTL_FILTER_TYPE_BELL = 1 + +const SA_CTL_FILTER_TYPE_NOTCH = 2 + +const SA_CTL_FILTER_TYPE_LOW_PASS = 3 + +const SA_CTL_CL_TYPE_PID = 0 + +const SA_CTL_CL_TYPE_ADVANCED = 1 + +const SA_CTL_VERSION_MAJOR = 1 + +const SA_CTL_VERSION_MINOR = 6 + +const SA_CTL_VERSION_UPDATE = 0 + +#const SA_CTL_API = __declspec(dllimport) + +# Skipping MacroDefinition: SA_CTL_CC __cdecl + diff --git a/src/hardware_implementations/smaract_stage/functions_smaract.jl b/src/hardware_implementations/smaract_stage/functions_smaract.jl new file mode 100644 index 0000000..a5314ed --- /dev/null +++ b/src/hardware_implementations/smaract_stage/functions_smaract.jl @@ -0,0 +1,184 @@ +function SA_CTL_GetFullVersionString() + ccall((:SA_CTL_GetFullVersionString, SmarAct), Ptr{Cchar}, ()) +end + +function SA_CTL_GetResultInfo(result) + ccall((:SA_CTL_GetResultInfo, SmarAct), Ptr{Cchar}, (SA_CTL_Result_t,), result) +end + +function SA_CTL_GetEventInfo(event) + ccall((:SA_CTL_GetEventInfo, SmarAct), Ptr{Cchar}, (Ptr{SA_CTL_Event_t},), event) +end + +function SA_CTL_Open(dHandle, locator, config) + ccall((:SA_CTL_Open, SmarAct), SA_CTL_Result_t, (Ptr{SA_CTL_DeviceHandle_t}, Ptr{Cchar}, Ptr{Cchar}), dHandle, locator, config) +end + +function SA_CTL_Close(dHandle) + ccall((:SA_CTL_Close, SmarAct), SA_CTL_Result_t, (SA_CTL_DeviceHandle_t,), dHandle) +end + +function SA_CTL_Cancel(dHandle) + ccall((:SA_CTL_Cancel, SmarAct), SA_CTL_Result_t, (SA_CTL_DeviceHandle_t,), dHandle) +end + +function SA_CTL_FindDevices(options, deviceList, deviceListLen) + ccall((:SA_CTL_FindDevices, SmarAct), SA_CTL_Result_t, (Ptr{Cchar}, Ptr{Cchar}, Ptr{Csize_t}), options, deviceList, deviceListLen) +end + +function SA_CTL_GetProperty_i32(dHandle, idx, pkey, value, ioArraySize) + ccall((:SA_CTL_GetProperty_i32, SmarAct), SA_CTL_Result_t, (SA_CTL_DeviceHandle_t, Int8, SA_CTL_PropertyKey_t, Ptr{Int32}, Ptr{Csize_t}), dHandle, idx, pkey, value, ioArraySize) +end + +function SA_CTL_GetPropertyBuffer_i32(dHandle, idx, pkey, value, ioBufferSize) + ccall((:SA_CTL_GetPropertyBuffer_i32, SmarAct), SA_CTL_Result_t, (SA_CTL_DeviceHandle_t, Int8, SA_CTL_PropertyKey_t, Ptr{Int32}, Ptr{Csize_t}), dHandle, idx, pkey, value, ioBufferSize) +end + +function SA_CTL_SetProperty_i32(dHandle, idx, pkey, value) + ccall((:SA_CTL_SetProperty_i32, SmarAct), SA_CTL_Result_t, (SA_CTL_DeviceHandle_t, Int8, SA_CTL_PropertyKey_t, Int32), dHandle, idx, pkey, value) +end + +function SA_CTL_SetPropertyArray_i32(dHandle, idx, pkey, values, arraySize) + ccall((:SA_CTL_SetPropertyArray_i32, SmarAct), SA_CTL_Result_t, (SA_CTL_DeviceHandle_t, Int8, SA_CTL_PropertyKey_t, Ptr{Int32}, Csize_t), dHandle, idx, pkey, values, arraySize) +end + +function SA_CTL_SetPropertyBuffer_i32(dHandle, idx, pkey, values, bufferSize) + ccall((:SA_CTL_SetPropertyBuffer_i32, SmarAct), SA_CTL_Result_t, (SA_CTL_DeviceHandle_t, Int8, SA_CTL_PropertyKey_t, Ptr{Int32}, Csize_t), dHandle, idx, pkey, values, bufferSize) +end + +function SA_CTL_GetProperty_i64(dHandle, idx, pkey, value, ioArraySize) + ccall((:SA_CTL_GetProperty_i64, SmarAct), SA_CTL_Result_t, (SA_CTL_DeviceHandle_t, Int8, SA_CTL_PropertyKey_t, Ptr{Int64}, Ptr{Csize_t}), dHandle, idx, pkey, value, ioArraySize) +end + +function SA_CTL_GetPropertyBuffer_i64(dHandle, idx, pkey, value, ioBufferSize) + ccall((:SA_CTL_GetPropertyBuffer_i64, SmarAct), SA_CTL_Result_t, (SA_CTL_DeviceHandle_t, Int8, SA_CTL_PropertyKey_t, Ptr{Int64}, Ptr{Csize_t}), dHandle, idx, pkey, value, ioBufferSize) +end + +function SA_CTL_SetProperty_i64(dHandle, idx, pkey, value) + ccall((:SA_CTL_SetProperty_i64, SmarAct), SA_CTL_Result_t, (SA_CTL_DeviceHandle_t, Int8, SA_CTL_PropertyKey_t, Int64), dHandle, idx, pkey, value) +end + +function SA_CTL_SetPropertyArray_i64(dHandle, idx, pkey, values, arraySize) + ccall((:SA_CTL_SetPropertyArray_i64, SmarAct), SA_CTL_Result_t, (SA_CTL_DeviceHandle_t, Int8, SA_CTL_PropertyKey_t, Ptr{Int64}, Csize_t), dHandle, idx, pkey, values, arraySize) +end + +function SA_CTL_SetPropertyBuffer_i64(dHandle, idx, pkey, values, bufferSize) + ccall((:SA_CTL_SetPropertyBuffer_i64, SmarAct), SA_CTL_Result_t, (SA_CTL_DeviceHandle_t, Int8, SA_CTL_PropertyKey_t, Ptr{Int64}, Csize_t), dHandle, idx, pkey, values, bufferSize) +end + +function SA_CTL_GetProperty_s(dHandle, idx, pkey, value, ioArraySize) + ccall((:SA_CTL_GetProperty_s, SmarAct), SA_CTL_Result_t, (SA_CTL_DeviceHandle_t, Int8, SA_CTL_PropertyKey_t, Ptr{Cchar}, Ptr{Csize_t}), dHandle, idx, pkey, value, ioArraySize) +end + +function SA_CTL_SetProperty_s(dHandle, idx, pkey, value) + ccall((:SA_CTL_SetProperty_s, SmarAct), SA_CTL_Result_t, (SA_CTL_DeviceHandle_t, Int8, SA_CTL_PropertyKey_t, Ptr{Cchar}), dHandle, idx, pkey, value) +end + +function SA_CTL_RequestReadProperty(dHandle, idx, pkey, rID, tHandle) + ccall((:SA_CTL_RequestReadProperty, SmarAct), SA_CTL_Result_t, (SA_CTL_DeviceHandle_t, Int8, SA_CTL_PropertyKey_t, Ptr{SA_CTL_RequestID_t}, SA_CTL_TransmitHandle_t), dHandle, idx, pkey, rID, tHandle) +end + +function SA_CTL_ReadProperty_i32(dHandle, rID, value, ioArraySize) + ccall((:SA_CTL_ReadProperty_i32, SmarAct), SA_CTL_Result_t, (SA_CTL_DeviceHandle_t, SA_CTL_RequestID_t, Ptr{Int32}, Ptr{Csize_t}), dHandle, rID, value, ioArraySize) +end + +function SA_CTL_ReadProperty_i64(dHandle, rID, value, ioArraySize) + ccall((:SA_CTL_ReadProperty_i64, SmarAct), SA_CTL_Result_t, (SA_CTL_DeviceHandle_t, SA_CTL_RequestID_t, Ptr{Int64}, Ptr{Csize_t}), dHandle, rID, value, ioArraySize) +end + +function SA_CTL_ReadProperty_s(dHandle, rID, value, ioArraySize) + ccall((:SA_CTL_ReadProperty_s, SmarAct), SA_CTL_Result_t, (SA_CTL_DeviceHandle_t, SA_CTL_RequestID_t, Ptr{Cchar}, Ptr{Csize_t}), dHandle, rID, value, ioArraySize) +end + +function SA_CTL_RequestWriteProperty_i32(dHandle, idx, pkey, value, rID, tHandle) + ccall((:SA_CTL_RequestWriteProperty_i32, SmarAct), SA_CTL_Result_t, (SA_CTL_DeviceHandle_t, Int8, SA_CTL_PropertyKey_t, Int32, Ptr{SA_CTL_RequestID_t}, SA_CTL_TransmitHandle_t), dHandle, idx, pkey, value, rID, tHandle) +end + +function SA_CTL_RequestWriteProperty_i64(dHandle, idx, pkey, value, rID, tHandle) + ccall((:SA_CTL_RequestWriteProperty_i64, SmarAct), SA_CTL_Result_t, (SA_CTL_DeviceHandle_t, Int8, SA_CTL_PropertyKey_t, Int64, Ptr{SA_CTL_RequestID_t}, SA_CTL_TransmitHandle_t), dHandle, idx, pkey, value, rID, tHandle) +end + +function SA_CTL_RequestWriteProperty_s(dHandle, idx, pkey, value, rID, tHandle) + ccall((:SA_CTL_RequestWriteProperty_s, SmarAct), SA_CTL_Result_t, (SA_CTL_DeviceHandle_t, Int8, SA_CTL_PropertyKey_t, Ptr{Cchar}, Ptr{SA_CTL_RequestID_t}, SA_CTL_TransmitHandle_t), dHandle, idx, pkey, value, rID, tHandle) +end + +function SA_CTL_RequestWritePropertyArray_i32(dHandle, idx, pkey, values, arraySize, rID, tHandle) + ccall((:SA_CTL_RequestWritePropertyArray_i32, SmarAct), SA_CTL_Result_t, (SA_CTL_DeviceHandle_t, Int8, SA_CTL_PropertyKey_t, Ptr{Int32}, Csize_t, Ptr{SA_CTL_RequestID_t}, SA_CTL_TransmitHandle_t), dHandle, idx, pkey, values, arraySize, rID, tHandle) +end + +function SA_CTL_RequestWritePropertyArray_i64(dHandle, idx, pkey, values, arraySize, rID, tHandle) + ccall((:SA_CTL_RequestWritePropertyArray_i64, SmarAct), SA_CTL_Result_t, (SA_CTL_DeviceHandle_t, Int8, SA_CTL_PropertyKey_t, Ptr{Int64}, Csize_t, Ptr{SA_CTL_RequestID_t}, SA_CTL_TransmitHandle_t), dHandle, idx, pkey, values, arraySize, rID, tHandle) +end + +function SA_CTL_WaitForWrite(dHandle, rID) + ccall((:SA_CTL_WaitForWrite, SmarAct), SA_CTL_Result_t, (SA_CTL_DeviceHandle_t, SA_CTL_RequestID_t), dHandle, rID) +end + +function SA_CTL_CancelRequest(dHandle, rID) + ccall((:SA_CTL_CancelRequest, SmarAct), SA_CTL_Result_t, (SA_CTL_DeviceHandle_t, SA_CTL_RequestID_t), dHandle, rID) +end + +function SA_CTL_CreateOutputBuffer(dHandle, tHandle) + ccall((:SA_CTL_CreateOutputBuffer, SmarAct), SA_CTL_Result_t, (SA_CTL_DeviceHandle_t, Ptr{SA_CTL_TransmitHandle_t}), dHandle, tHandle) +end + +function SA_CTL_FlushOutputBuffer(dHandle, tHandle) + ccall((:SA_CTL_FlushOutputBuffer, SmarAct), SA_CTL_Result_t, (SA_CTL_DeviceHandle_t, SA_CTL_TransmitHandle_t), dHandle, tHandle) +end + +function SA_CTL_CancelOutputBuffer(dHandle, tHandle) + ccall((:SA_CTL_CancelOutputBuffer, SmarAct), SA_CTL_Result_t, (SA_CTL_DeviceHandle_t, SA_CTL_TransmitHandle_t), dHandle, tHandle) +end + +function SA_CTL_OpenCommandGroup(dHandle, tHandle, triggerMode) + ccall((:SA_CTL_OpenCommandGroup, SmarAct), SA_CTL_Result_t, (SA_CTL_DeviceHandle_t, Ptr{SA_CTL_TransmitHandle_t}, UInt32), dHandle, tHandle, triggerMode) +end + +function SA_CTL_CloseCommandGroup(dHandle, tHandle) + ccall((:SA_CTL_CloseCommandGroup, SmarAct), SA_CTL_Result_t, (SA_CTL_DeviceHandle_t, SA_CTL_TransmitHandle_t), dHandle, tHandle) +end + +function SA_CTL_CancelCommandGroup(dHandle, tHandle) + ccall((:SA_CTL_CancelCommandGroup, SmarAct), SA_CTL_Result_t, (SA_CTL_DeviceHandle_t, SA_CTL_TransmitHandle_t), dHandle, tHandle) +end + +function SA_CTL_WaitForEvent(dHandle, event, timeout) + ccall((:SA_CTL_WaitForEvent, SmarAct), SA_CTL_Result_t, (SA_CTL_DeviceHandle_t, Ptr{SA_CTL_Event_t}, UInt32), dHandle, event, timeout) +end + +function SA_CTL_Calibrate(dHandle, idx, tHandle) + ccall((:SA_CTL_Calibrate, SmarAct), SA_CTL_Result_t, (SA_CTL_DeviceHandle_t, Int8, SA_CTL_TransmitHandle_t), dHandle, idx, tHandle) +end + +function SA_CTL_Reference(dHandle, idx, tHandle) + ccall((:SA_CTL_Reference, SmarAct), SA_CTL_Result_t, (SA_CTL_DeviceHandle_t, Int8, SA_CTL_TransmitHandle_t), dHandle, idx, tHandle) +end + +function SA_CTL_Move(dHandle, idx, moveValue, tHandle) + ccall((:SA_CTL_Move, SmarAct), SA_CTL_Result_t, (SA_CTL_DeviceHandle_t, Int8, Int64, SA_CTL_TransmitHandle_t), dHandle, idx, moveValue, tHandle) +end + +function SA_CTL_Stop(dHandle, idx, tHandle) + ccall((:SA_CTL_Stop, SmarAct), SA_CTL_Result_t, (SA_CTL_DeviceHandle_t, Int8, SA_CTL_TransmitHandle_t), dHandle, idx, tHandle) +end + +function SA_CTL_StopExt(dHandle, idx, stopOptions, tHandle) + ccall((:SA_CTL_StopExt, SmarAct), SA_CTL_Result_t, (SA_CTL_DeviceHandle_t, Int8, UInt32, SA_CTL_TransmitHandle_t), dHandle, idx, stopOptions, tHandle) +end + +function SA_CTL_OpenStream(dHandle, sHandle, triggerMode) + ccall((:SA_CTL_OpenStream, SmarAct), SA_CTL_Result_t, (SA_CTL_DeviceHandle_t, Ptr{SA_CTL_StreamHandle_t}, UInt32), dHandle, sHandle, triggerMode) +end + +function SA_CTL_StreamFrame(dHandle, sHandle, frameData, frameSize) + ccall((:SA_CTL_StreamFrame, SmarAct), SA_CTL_Result_t, (SA_CTL_DeviceHandle_t, SA_CTL_StreamHandle_t, Ptr{UInt8}, UInt32), dHandle, sHandle, frameData, frameSize) +end + +function SA_CTL_CloseStream(dHandle, sHandle) + ccall((:SA_CTL_CloseStream, SmarAct), SA_CTL_Result_t, (SA_CTL_DeviceHandle_t, SA_CTL_StreamHandle_t), dHandle, sHandle) +end + +function SA_CTL_AbortStream(dHandle, sHandle) + ccall((:SA_CTL_AbortStream, SmarAct), SA_CTL_Result_t, (SA_CTL_DeviceHandle_t, SA_CTL_StreamHandle_t), dHandle, sHandle) +end + diff --git a/src/hardware_implementations/smaract_stage/helper_smaract.jl b/src/hardware_implementations/smaract_stage/helper_smaract.jl new file mode 100644 index 0000000..3298101 --- /dev/null +++ b/src/hardware_implementations/smaract_stage/helper_smaract.jl @@ -0,0 +1,297 @@ + +function _check!(errcode::SA_CTL_Result_t; msg::String = "Operation failed") + if errcode != SA_CTL_ERROR_NONE + sdk_msg = unsafe_string(SA_CTL_GetResultInfo(errcode)) + error("$msg [SDK: $sdk_msg (0x$(string(errcode, base=16)))]") + end +end + +# Property read/write convenience wrappers +function _get_i32(stage::MCS2Stage, ch::Int32, pkey) + val = Ref{Int32}() + _check!(SA_CTL_GetProperty_i32(stage.dHandle[], ch, pkey, val, Ref{Csize_t}(1)), + msg = "GetProperty_i32 ch=$ch pkey=0x$(string(pkey,base=16))") + return val[] +end + +function _get_i64(stage::MCS2Stage, ch::Int32, pkey) + val = Ref{Int64}() + _check!(SA_CTL_GetProperty_i64(stage.dHandle[], ch, pkey, val, Ref{Csize_t}(1)), + msg = "GetProperty_i64 ch=$ch pkey=0x$(string(pkey,base=16))") + return val[] +end + +function _set_i32(stage::MCS2Stage, ch::Int32, pkey, value::Int32) + _check!(SA_CTL_SetProperty_i32(stage.dHandle[], ch, pkey, value), + msg = "SetProperty_i32 ch=$ch pkey=0x$(string(pkey,base=16))") +end + +function _set_i64(stage::MCS2Stage, ch::Int32, pkey, value::Int64) + _check!(SA_CTL_SetProperty_i64(stage.dHandle[], ch, pkey, value), + msg = "SetProperty_i64 ch=$ch pkey=0x$(string(pkey,base=16))") +end + +# Query current position from hardware and update stage struct + +function query_positions!(stage::MCS2Stage) + for (i, ch) in enumerate(stage.channel_ids) + stage.connected[i] || continue # skip channels with no positioner + stage.pos_pm[i] = _get_i64(stage, ch, SA_CTL_PKEY_POSITION) + end + @info "Positions (µm): $(round.(stage.pos_pm ./ 1e6, digits=3))" +end + +# Query and cache channel state flags + +function query_channel_states!(stage::MCS2Stage) + for (i, ch) in enumerate(stage.channel_ids) + stage.connected[i] || continue # skip channels with no positioner + state = _get_i32(stage, ch, SA_CTL_PKEY_CHANNEL_STATE) + stage.is_calibrated[i] = (state & SA_CTL_CH_STATE_BIT_IS_CALIBRATED) != 0 + stage.is_referenced[i] = (state & SA_CTL_CH_STATE_BIT_IS_REFERENCED) != 0 + end +end + +# Set velocity and acceleration + +function set_velocity!(stage::MCS2Stage, vel_pm_s::Int64) + for (i, ch) in enumerate(stage.channel_ids) + stage.connected[i] || continue # skip channels with no positioner + _set_i64(stage, ch, SA_CTL_PKEY_MOVE_VELOCITY, vel_pm_s) + stage.velocity_pm_s[i] = vel_pm_s + end + @info "Velocity set to $(vel_pm_s / 1e9) mm/s" +end + +function set_acceleration!(stage::MCS2Stage, accel_pm_s2::Int64) + for (i, ch) in enumerate(stage.channel_ids) + stage.connected[i] || continue # skip channels with no positioner + _set_i64(stage, ch, SA_CTL_PKEY_MOVE_ACCELERATION, accel_pm_s2) + stage.accel_pm_s2[i] = accel_pm_s2 + end + @info "Acceleration set to $(accel_pm_s2 / 1e9) mm/s²" +end + +# Referencing + +function find_reference!(stage::MCS2Stage, ch_index::Int; timeout_s::Float64 = 60.0) + ch = stage.channel_ids[ch_index] + + if !stage.connected[ch_index] + @warn "Channel $ch has no positioner attached — skipping referencing." + return + end + + @info "Referencing channel $ch ..." + + # Default referencing options (0 = forward, no special flags) + _set_i32(stage, ch, SA_CTL_PKEY_REFERENCING_OPTIONS, Int32(0)) + + _check!(SA_CTL_Reference(stage.dHandle[], ch, Int32(0)), + msg = "Failed to start referencing on channel $ch") + + t0 = time() + while true + state = _get_i32(stage, ch, SA_CTL_PKEY_CHANNEL_STATE) + referencing = (state & SA_CTL_CH_STATE_BIT_REFERENCING) != 0 + referencing || break + time() - t0 > timeout_s && error("Referencing timeout on channel $ch after $(timeout_s)s") + sleep(0.1) + end + + stage.is_referenced[ch_index] = true + @info "Channel $ch referenced." +end + +# Absolute move for a single channel + +function move_abs!(stage::MCS2Stage, ch_index::Int, target_pm::Int64; + timeout_s::Float64 = 30.0) + ch = stage.channel_ids[ch_index] + + if !stage.connected[ch_index] + @warn "Channel $ch has no positioner attached — move ignored." + return + end + + # Always set MOVE_MODE before moving. Without this the device uses whatever mode was + # last active, which could be relative or step mode — leading to completely wrong positions. + _set_i32(stage, ch, SA_CTL_PKEY_MOVE_MODE, Int32(SA_CTL_MOVE_MODE_CL_ABSOLUTE)) + + @info "Moving channel $ch to $(target_pm / 1e6) µm ..." + _check!(SA_CTL_Move(stage.dHandle[], ch, target_pm, Int32(0)), + msg = "Move command failed on channel $ch") + + # Poll until not moving + t0 = time() + while true + state = _get_i32(stage, ch, SA_CTL_PKEY_CHANNEL_STATE) + moving = (state & SA_CTL_CH_STATE_BIT_ACTIVELY_MOVING) != 0 + moving || break + if time() - t0 > timeout_s + SA_CTL_Stop(stage.dHandle[], ch, Int32(0)) + error("Move timeout on channel $ch — stop sent") + end + sleep(0.05) + end + + # Refresh position + stage.pos_pm[ch_index] = _get_i64(stage, ch, SA_CTL_PKEY_POSITION) + @info "Channel $ch at $(stage.pos_pm[ch_index] / 1e6) µm" +end + + +""" + move_all!(stage, targets_pm) + +Sends absolute move commands to all CONNECTED channels simultaneously, +then waits for all of them to finish. `targets_pm` is a vector of Int64 +positions, one per channel — entries for disconnected channels (e.g. +channel 2 on an XY-only stage) are simply ignored. +""" +function move_all!(stage::MCS2Stage, targets_pm::Vector{Int64}; timeout_s::Float64 = 30.0) + length(targets_pm) == stage.n_channels || + error("targets_pm length $(length(targets_pm)) ≠ n_channels $(stage.n_channels)") + + # Set mode and fire moves only for connected channels + moving_channels = Int32[] + for (i, ch) in enumerate(stage.channel_ids) + stage.connected[i] || continue # skip channels with no positioner + _set_i32(stage, ch, SA_CTL_PKEY_MOVE_MODE, Int32(SA_CTL_MOVE_MODE_CL_ABSOLUTE)) + _check!(SA_CTL_Move(stage.dHandle[], ch, targets_pm[i], Int32(0)), + msg = "Move command failed on channel $ch") + push!(moving_channels, ch) + end + + # Wait for those channels to finish + t0 = time() + @async begin + while true + all_done = true + for ch in moving_channels + state = _get_i32(stage, ch, SA_CTL_PKEY_CHANNEL_STATE) + moving = (state & SA_CTL_CH_STATE_BIT_ACTIVELY_MOVING) != 0 + moving && (all_done = false; break) + end + all_done && break + if time() - t0 > timeout_s + for ch in moving_channels + SA_CTL_Stop(stage.dHandle[], ch, Int32(0)) + end + error("Move-all timeout after $(timeout_s)s — all channels stopped") + end + sleep(0.05) + end + end + # Refresh all positions + query_positions!(stage) +end + +# Stop a single channel +""" + stop_channel!(stage, ch_index) + +Immediately stops motion on one channel (1-based index). No-op if the +channel has no positioner attached. +""" +function stop_channel!(stage::MCS2Stage, ch_index::Int) + stage.connected[ch_index] || return + ch = stage.channel_ids[ch_index] + SA_CTL_Stop(stage.dHandle[], ch, Int32(0)) + @info "Stop sent to channel $ch" +end + +""" + stop_all!(stage) + +Stops all CONNECTED channels. +""" +function stop_all!(stage::MCS2Stage) + for (i, ch) in enumerate(stage.channel_ids) + stage.connected[i] || continue # skip channels with no positioner + SA_CTL_Stop(stage.dHandle[], ch, Int32(0)) + end + @info "Stop sent to all connected channels" +end + +# Find physical travel range via end-stop detection +""" + find_travel_range!(stage, ch_index; overshoot_pm=70_000_000_000, timeout_s=60.0) + +Discovers the PHYSICAL travel range of one channel by driving it to each +mechanical end stop and recording where it actually stops. + +This is different from `stage.min_pm` / `stage.max_pm`, which are SOFTWARE +limits (see SA_CTL_PKEY_RANGE_LIMIT_MIN/MAX in the manual). By default those +are 0/0 — "no software limit configured" — NOT "zero physical range". The +MCS2 has no limit-switch property to query directly; instead the controller +detects a mechanical end stop *while moving* and sets the +END_STOP_REACHED state bit. + + +""" +function find_travel_range!(stage::MCS2Stage, ch_index::Int; + overshoot_pm::Int64 = 70_000_000_000, + timeout_s::Float64 = 60.0) + ch = stage.channel_ids[ch_index] + + if !stage.connected[ch_index] + @warn "Channel $ch has no positioner attached — cannot find travel range." + return (Int64(0), Int64(0)) + end + if !stage.is_referenced[ch_index] + error("Channel $ch is not referenced. Call find_reference!(stage, $ch_index) first.") + end + + # --- Drive to negative end stop ---------------------------------------- + @info "Channel $ch: driving to negative end stop ..." + _drive_to_endstop!(stage, ch, -overshoot_pm, timeout_s) + min_pm = _get_i64(stage, ch, SA_CTL_PKEY_POSITION) + @info "Channel $ch: negative end stop at $(min_pm / 1e6) µm" + + # --- Drive to positive end stop ---------------------------------------- + @info "Channel $ch: driving to positive end stop ..." + _drive_to_endstop!(stage, ch, overshoot_pm, timeout_s) + max_pm = _get_i64(stage, ch, SA_CTL_PKEY_POSITION) + @info "Channel $ch: positive end stop at $(max_pm / 1e6) µm" + + range_mm = (max_pm - min_pm) / 1e9 + @info "Channel $ch: physical travel range ≈ $(range_mm) mm" + + # Update the stage struct with the discovered physical limits. + stage.min_pm[ch_index] = min_pm + stage.max_pm[ch_index] = max_pm + + return (min_pm, max_pm) +end + +""" + _drive_to_endstop!(stage, ch, target_pm, timeout_s) + +Internal helper for `find_travel_range!`. Sends an absolute move to +`target_pm` (deliberately beyond the real travel range) and waits until +the channel stops — either because it arrived (won't happen here) or +because END_STOP_REACHED / MOVEMENT_FAILED was set. + +Unlike `move_abs!`, this does NOT treat a stopped/failed move as an error — +hitting the end stop is the expected and desired outcome. +""" +function _drive_to_endstop!(stage::MCS2Stage, ch::Int32, target_pm::Int64, timeout_s::Float64) + _set_i32(stage, ch, SA_CTL_PKEY_MOVE_MODE, Int32(SA_CTL_MOVE_MODE_CL_ABSOLUTE)) + _check!(SA_CTL_Move(stage.dHandle[], ch, target_pm, Int32(0)), + msg = "Move command failed on channel $ch") + + t0 = time() + while true + state = _get_i32(stage, ch, SA_CTL_PKEY_CHANNEL_STATE) + moving = (state & SA_CTL_CH_STATE_BIT_ACTIVELY_MOVING) != 0 + moving || break + if time() - t0 > timeout_s + SA_CTL_Stop(stage.dHandle[], ch, Int32(0)) + error("Channel $ch: timed out finding end stop after $(timeout_s)s") + end + sleep(0.05) + end + + SA_CTL_Stop(stage.dHandle[], ch, Int32(0)) +end \ No newline at end of file diff --git a/src/hardware_implementations/smaract_stage/interface_methods_smaract.jl b/src/hardware_implementations/smaract_stage/interface_methods_smaract.jl new file mode 100644 index 0000000..fb68ce0 --- /dev/null +++ b/src/hardware_implementations/smaract_stage/interface_methods_smaract.jl @@ -0,0 +1,222 @@ + +""" + initialize!(stage::MCS2Stage) + +Discovers the first available MCS2 device, opens it, configures all +channels (CLF, hold time, velocity, acceleration), and reads travel limits. + +After this call, `stage.connectionstatus == true` and `stage.pos_pm` holds +the current hardware positions. +""" +function initialize!(stage::MCS2Stage) + if stage.connectionstatus + @error "Stage already initialized — call shutdown!(stage) first." + return + end + + # Find devices + bufsize = 1024 + device_buf = Vector{Cchar}(undef, bufsize) + device_len = Ref{Csize_t}(bufsize) + + result = SA_CTL_FindDevices("", device_buf, device_len) + if result != SA_CTL_ERROR_NONE + @error "SA_CTL_FindDevices failed: $(unsafe_string(SA_CTL_GetResultInfo(result)))" + return + end + + locator = unsafe_string(pointer(device_buf)) + if isempty(locator) + @error "No SmarAct MCS2 devices found. Check USB/Ethernet connection." + return + end + @info "Device found: $locator" + + # Open device + result = SA_CTL_Open(stage.dHandle, locator, C_NULL) + if result != SA_CTL_ERROR_NONE + @error "SA_CTL_Open failed: $(unsafe_string(SA_CTL_GetResultInfo(result)))" + return + end + stage.connectionstatus = true + @info "Device opened. Handle: $(stage.dHandle[])" + + # Read actual channel count and trim struct if needed + n_ch_ref = Ref{Int32}() + SA_CTL_GetProperty_i32(stage.dHandle[], Int32(0), + SA_CTL_PKEY_NUMBER_OF_CHANNELS, n_ch_ref, Ref{Csize_t}(1)) + hw_channels = Int(n_ch_ref[]) + if hw_channels < stage.n_channels + @warn "Device has $hw_channels channels; stage configured for $(stage.n_channels). Truncating." + stage.n_channels = hw_channels + resize!(stage.channel_ids, hw_channels) + resize!(stage.pos_pm, hw_channels) + resize!(stage.min_pm, hw_channels) + resize!(stage.max_pm, hw_channels) + resize!(stage.home_pm, hw_channels) + resize!(stage.velocity_pm_s, hw_channels) + resize!(stage.accel_pm_s2, hw_channels) + resize!(stage.is_calibrated, hw_channels) + resize!(stage.is_referenced, hw_channels) + resize!(stage.connected, hw_channels) + end + + # Per-channel setup + for (i, ch) in enumerate(stage.channel_ids) + # Detect whether a positioner is physically attached + ch_state = Ref{Int32}() + state_result = SA_CTL_GetProperty_i32(stage.dHandle[], ch, + SA_CTL_PKEY_CHANNEL_STATE, ch_state, Ref{Csize_t}(1)) + if state_result != SA_CTL_ERROR_NONE + @warn "Channel $ch: could not read CHANNEL_STATE ($(unsafe_string(SA_CTL_GetResultInfo(state_result)))) — marking as not connected." + stage.connected[i] = false + continue + end + sensor_present = (ch_state[] & SA_CTL_CH_STATE_BIT_SENSOR_PRESENT) != 0 + stage.connected[i] = sensor_present + + if !sensor_present + @info "Channel $ch: no positioner detected — skipping motion setup. (Shown as N/C in GUI.)" + continue + end + + # Amplifier-side settings (safe to set; channel is connected) + try + SA_CTL_SetProperty_i32(stage.dHandle[], ch, + SA_CTL_PKEY_MAX_CL_FREQUENCY, Int32(18500)) + SA_CTL_SetProperty_i32(stage.dHandle[], ch, + SA_CTL_PKEY_HOLD_TIME, SA_CTL_HOLD_TIME_INFINITE) + SA_CTL_SetProperty_i64(stage.dHandle[], ch, + SA_CTL_PKEY_MOVE_VELOCITY, stage.velocity_pm_s[i]) + SA_CTL_SetProperty_i64(stage.dHandle[], ch, + SA_CTL_PKEY_MOVE_ACCELERATION, stage.accel_pm_s2[i]) + catch e + @warn "Channel $ch: failed to set motion parameters ($e). Marking as not connected." + stage.connected[i] = false + continue + end + + # Travel limits (sensor-dependent; only read if sensor present) + lim_min = Ref{Int64}() + lim_max = Ref{Int64}() + r1 = SA_CTL_GetProperty_i64(stage.dHandle[], ch, + SA_CTL_PKEY_RANGE_LIMIT_MIN, lim_min, Ref{Csize_t}(1)) + r2 = SA_CTL_GetProperty_i64(stage.dHandle[], ch, + SA_CTL_PKEY_RANGE_LIMIT_MAX, lim_max, Ref{Csize_t}(1)) + if r1 == SA_CTL_ERROR_NONE && r2 == SA_CTL_ERROR_NONE + stage.min_pm[i] = lim_min[] + stage.max_pm[i] = lim_max[] + else + @warn "Channel $ch: could not read travel range — leaving default limits." + end + end + + # Query initial positions and state + query_positions!(stage) + query_channel_states!(stage) + + @info "$(stage.stagelabel) initialized ($(stage.n_channels) channel(s))." +end + + +""" + shutdown!(stage::MCS2Stage) + +Closes the device connection. Safe to call even if not connected. +""" +function shutdown!(stage::MCS2Stage) + if !stage.connectionstatus + @info "Stage not connected — nothing to shut down." + return + end + result = SA_CTL_Close(stage.dHandle[]) + if result != SA_CTL_ERROR_NONE + @warn "SA_CTL_Close error: $(unsafe_string(SA_CTL_GetResultInfo(result)))" + else + @info "$(stage.stagelabel) disconnected." + end + stage.connectionstatus = false +end + + +""" + move!(stage, targets_pm::Vector{Int64}) + +Moves all channels to absolute positions given in picometres, then +refreshes `stage.pos_pm`. +""" +function move!(stage::MCS2Stage, targets_pm::Vector{Int64}) + move_all!(stage, targets_pm) + # move_all! already calls query_positions! internally +end + +""" + move_um!(stage, targets_um::Vector{Float64}) + +Convenience overload: supply positions in micrometres (Float64). +Internally converts to Int64 picometres. +""" +function move_um!(stage::MCS2Stage, targets_um::Vector{Float64}) + targets_pm = round.(Int64, targets_um .* 1e6) + move!(stage, targets_pm) +end + + +""" + getposition!(stage) -> Vector{Int64} + +Queries the current position of all channels, updates `stage.pos_pm`, +and returns the values in picometres. +""" +function getposition!(stage::MCS2Stage) :: Vector{Int64} + query_positions!(stage) + return copy(stage.pos_pm) +end + + +""" + home!(stage) + +Moves all channels to `stage.home_pm` (default: all zeros). +""" +function home!(stage::MCS2Stage) + @info "Moving to home position ..." + move!(stage, stage.home_pm) +end + + +""" + stopmotion!(stage) + +Immediately stops all channels. +""" +function stopmotion!(stage::MCS2Stage) + stop_all!(stage) +end + + +""" + export_state(stage::MCS2Stage) -> (attributes, data, children) + +Returns a tuple of (Dict, nothing, Dict) for compatibility with the +MicroscopeControl state serialisation convention used by the PI module. +""" +function export_state(stage::MCS2Stage) + attributes = Dict{String, Any}( + "stage_label" => stage.stagelabel, + "n_channels" => stage.n_channels, + "channel_ids" => copy(stage.channel_ids), + "connected" => stage.connectionstatus, + "handle" => stage.dHandle[], + "position_pm" => copy(stage.pos_pm), + "position_um" => stage.pos_pm ./ 1e6, + "min_pm" => copy(stage.min_pm), + "max_pm" => copy(stage.max_pm), + "home_pm" => copy(stage.home_pm), + "velocity_pm_s" => copy(stage.velocity_pm_s), + "accel_pm_s2" => copy(stage.accel_pm_s2), + "is_calibrated" => copy(stage.is_calibrated), + "is_referenced" => copy(stage.is_referenced), + ) + return attributes, nothing, Dict{String,Any}() +end diff --git a/src/hardware_implementations/smaract_stage/stageinterface_bridge_smaract.jl b/src/hardware_implementations/smaract_stage/stageinterface_bridge_smaract.jl new file mode 100644 index 0000000..dafb28d --- /dev/null +++ b/src/hardware_implementations/smaract_stage/stageinterface_bridge_smaract.jl @@ -0,0 +1,180 @@ +const PM_PER_UM = 1e6 + +""" + initialize(stage::MCS2Stage) + +Generic-interface entry point. Calls the existing `initialize!(stage)`, +then populates the Float64 µm fields (`real_x/y`, `targ_x/y`, `range_x/y`) +that the shared gui expects. +""" +function initialize(stage::MCS2Stage) + initialize!(stage) + + stage.range_x = (stage.min_pm[1] / PM_PER_UM, stage.max_pm[1] / PM_PER_UM) + stage.range_y = (stage.min_pm[2] / PM_PER_UM, stage.max_pm[2] / PM_PER_UM) + if stage.n_channels >= 3 + stage.range_z = (stage.min_pm[3] / PM_PER_UM, stage.max_pm[3] / PM_PER_UM) + end + + getposition(stage) # sync real_x/real_y from the freshly-queried pos_pm + stage.targ_x, stage.targ_y = stage.real_x, stage.real_y + if stage.n_channels >= 3 + stage.targ_z = stage.real_z + end + + # Sync servostatus (closed-loop on/off) from the actual hardware state, + # for every connected channel (skip channels with no positioner) + for i in 1:stage.n_channels + stage.connected[i] || continue + stage.servostatus[i] = _get_i32(stage, stage.channel_ids[i], SA_CTL_PKEY_CONTROL_LOOP_INPUT) != SA_CTL_CONTROL_LOOP_INPUT_DISABLED + end +end + +""" + shutdown(stage::MCS2Stage) + +Generic-interface entry point; thin wrapper around `shutdown!(stage)`. +""" +function shutdown(stage::MCS2Stage) + shutdown!(stage) +end + +""" + _apply_move!(stage::MCS2Stage, targets_um::Vector{Float64}) + +Shared implementation behind both `StageInterface.move` methods below. +`targets_um[i]` corresponds to `stage.channel_ids[i]`, in micrometres. +Channels with no positioner attached (`stage.connected[i] == false`) keep +their current position — same "skip disconnected channels" convention as +`_apply_servo!` and the rest of helper_smaract.jl. +""" +function _apply_move!(stage::MCS2Stage, targets_um::Vector{Float64}) + targets_pm = copy(stage.pos_pm) + + for i in eachindex(targets_um) + stage.connected[i] || continue # skip channels with no positioner + targets_pm[i] = round(Int64, targets_um[i] * PM_PER_UM) + end + + move!(stage, targets_pm) + + if stage.connected[1] + stage.targ_x = targets_um[1] + stage.real_x = stage.pos_pm[1] / PM_PER_UM + end + if stage.connected[2] + stage.targ_y = targets_um[2] + stage.real_y = stage.pos_pm[2] / PM_PER_UM + end + if length(targets_um) >= 3 && stage.connected[3] + stage.targ_z = targets_um[3] + stage.real_z = stage.pos_pm[3] / PM_PER_UM + end +end + +""" + StageInterface.move(stage::MCS2Stage, x::Float64, y::Float64) + +Used by gui2d. x, y in micrometres. See `_apply_move!`. +""" +function StageInterface.move(stage::MCS2Stage, x::Float64, y::Float64) + _apply_move!(stage, Float64[x, y]) +end + +""" + StageInterface.move(stage::MCS2Stage, x::Float64, y::Float64, z::Float64) + +Used by gui3d (the one your 3-channel stage's gui actually calls, since +`stage.dimensions == 3` routes it through gui3d). x, y, z in micrometres. +See `_apply_move!`. +""" +function StageInterface.move(stage::MCS2Stage, x::Float64, y::Float64, z::Float64) + _apply_move!(stage, Float64[x, y, z]) +end + +""" + StageInterface.getposition(stage::MCS2Stage) + +Refreshes `stage.pos_pm` from the hardware and mirrors channels 1/2 (and 3, +if present) into `real_x`/`real_y`/`real_z` (µm). +""" +function StageInterface.getposition(stage::MCS2Stage) + getposition!(stage) + + stage.real_x = stage.pos_pm[1] / PM_PER_UM + stage.real_y = stage.pos_pm[2] / PM_PER_UM + if stage.n_channels >= 3 + stage.real_z = stage.pos_pm[3] / PM_PER_UM + end +end + +""" + StageInterface.stopmotion(stage::MCS2Stage) + +Thin wrapper around `stopmotion!(stage)`. +""" +function StageInterface.stopmotion(stage::MCS2Stage) + stopmotion!(stage) +end + +""" + StageInterface.home(stage::MCS2Stage) + +Thin wrapper around `home!(stage)`; syncs `targ_x`/`targ_y` (and `targ_z`, +if a third channel exists) to the configured home position afterwards. +""" +function StageInterface.home(stage::MCS2Stage) + home!(stage) + + stage.targ_x = stage.home_pm[1] / PM_PER_UM + stage.targ_y = stage.home_pm[2] / PM_PER_UM + if stage.n_channels >= 3 + stage.targ_z = stage.home_pm[3] / PM_PER_UM + end + + getposition(stage) # refresh real_x/real_y once the move settles +end + +""" + _apply_servo!(stage::MCS2Stage, toggles::Vector{Bool}) + +Shared implementation behind both `StageInterface.servo` methods below. +`toggles[i]` corresponds to `stage.channel_ids[i]`. Channels with no +positioner physically attached (`stage.connected[i] == false`, populated +from the real CHANNEL_STATE query during `initialize!`) are silently +skipped — same "skip disconnected channels" convention already used +throughout helper_smaract.jl (move_all!, stop_all!, etc.), rather than +forcing a fixed dimensionality on the stage. +""" +function _apply_servo!(stage::MCS2Stage, toggles::Vector{Bool}) + for i in eachindex(toggles) + stage.connected[i] || continue # skip channels with no positioner + + ch = stage.channel_ids[i] + _set_i32(stage, ch, SA_CTL_PKEY_CONTROL_LOOP_INPUT, + toggles[i] ? Int32(SA_CTL_CONTROL_LOOP_INPUT_SENSOR) : Int32(SA_CTL_CONTROL_LOOP_INPUT_DISABLED)) + + stage.servostatus[i] = toggles[i] + end +end + +""" + StageInterface.servo(stage::MCS2Stage, xtoggle::Bool, ytoggle::Bool) + +Used by gui2d. See `_apply_servo!` — channels with no positioner attached +are skipped automatically. +""" +function StageInterface.servo(stage::MCS2Stage, xtoggle::Bool, ytoggle::Bool) + _apply_servo!(stage, Bool[xtoggle, ytoggle]) +end + +""" + StageInterface.servo(stage::MCS2Stage, xtoggle::Bool, ytoggle::Bool, ztoggle::Bool) + +Used by gui3d (this is the one your 3-channel stage's gui actually calls, +since `stage.dimensions == 3` routes it through gui3d). See `_apply_servo!` +— channels with no positioner attached are skipped automatically. +""" +function StageInterface.servo(stage::MCS2Stage, xtoggle::Bool, ytoggle::Bool, ztoggle::Bool) + _apply_servo!(stage, Bool[xtoggle, ytoggle, ztoggle]) +end \ No newline at end of file diff --git a/src/hardware_implementations/smaract_stage/test_dll.jl b/src/hardware_implementations/smaract_stage/test_dll.jl new file mode 100644 index 0000000..c19a870 --- /dev/null +++ b/src/hardware_implementations/smaract_stage/test_dll.jl @@ -0,0 +1,428 @@ + + +include("constants_smaract.jl") +include("functions_smaract.jl") + +const SmarAct = "C:\\Windows\\System32\\SmarActCTL.dll" + + +ptr = SA_CTL_GetFullVersionString() +version = unsafe_string(ptr) + +println("SmarActCTL library version: $(version).") + +function error_check!(errcode; msg="Operation failed") + if errcode != SA_CTL_ERROR_NONE + sdk_msg = unsafe_string(SA_CTL_GetResultInfo(errcode)) + error("$msg [SDK: $sdk_msg]") + end +end + + +# Find devices +bufsize = 1024 +deviceList = Vector{Cchar}(undef, bufsize) + +# Length variable (size_t *) +deviceListLen = Ref{Csize_t}(bufsize) + +# Call function +errcode = SA_CTL_FindDevices("", deviceList, deviceListLen) +error_check!(errcode, msg="Failed to find devices.") + +# Convert to Julia string (assumes null-terminated C string) +device_str = unsafe_string(pointer(deviceList)) + +if isempty(device_str) + @error "No devices found." + return +else + println("Devices found: $(device_str)") +end + +# open device +device = Ref{SA_CTL_DeviceHandle_t}() + + +locator = device_str +config = C_NULL + +# Call function +errcode = SA_CTL_Open(device,locator,config) + +# Check result (same style as your example) +error_check!(errcode, msg="Failed to open device.") + +dHandle = device[] + +println("Device opened successfully.") +println("Device handle: ", dHandle) + + +# get device info +function get_property_string(dHandle, idx, pkey; buf_len=SA_CTL_STRING_MAX_LENGTH+1) + buf = Vector{Cchar}(undef, buf_len) + ioSize = Ref{Csize_t}(buf_len) + errcode = SA_CTL_GetProperty_s(dHandle, idx, pkey, buf, ioSize) + error_check!(errcode, msg="Failed to get string property (pkey=$pkey, idx=$idx)") + return unsafe_string(pointer(buf)) +end + +function get_property_i32(dHandle, idx, pkey) + value = Ref{Int32}() + errcode = SA_CTL_GetProperty_i32(dHandle, idx, pkey, value, Ref{Csize_t}(1)) + error_check!(errcode, msg="Failed to get int32 property (pkey=$pkey, idx=$idx)") + return value[] +end + +function get_property_i64(dHandle, idx, pkey) + value = Ref{Int64}() + errcode = SA_CTL_GetProperty_i64(dHandle, idx, pkey, value, Ref{Csize_t}(1)) + error_check!(errcode) + return value[] +end + +println("\nDevice Serial Number: ", + get_property_string(dHandle, 0, SA_CTL_PKEY_DEVICE_SERIAL_NUMBER)) + +println("Device Name: ", + get_property_string(dHandle, 0, SA_CTL_PKEY_DEVICE_NAME)) + +type = get_property_i32(dHandle, 0, SA_CTL_PKEY_INTERFACE_TYPE) + +if type == SA_CTL_INTERFACE_USB + println("Interface Type: USB") +elseif type == SA_CTL_INTERFACE_ETHERNET + println("Interface Type: Ethernet") +end + +state = get_property_i32(dHandle, 0, SA_CTL_PKEY_DEVICE_STATE) + +println("Hand Control Module present: ", + (state & SA_CTL_DEV_STATE_BIT_HM_PRESENT) != 0 ? "yes" : "no") + +noOfBusModules = get_property_i32(dHandle, 0, SA_CTL_PKEY_NUMBER_OF_BUS_MODULES) +noOfChannels = get_property_i32(dHandle, 0, SA_CTL_PKEY_NUMBER_OF_CHANNELS) +println("Number of Bus Modules: ", noOfBusModules) +println("Total Number of Channels: ", noOfChannels) + +# ===== Module info ===== +for i in 0:(noOfBusModules - 1) + type = get_property_i32(dHandle, i, SA_CTL_PKEY_MODULE_TYPE) + print("Module $i") + + if type == SA_CTL_STICK_SLIP_PIEZO_DRIVER + println(" (Stick-Slip-Piezo-Driver):") + elseif type == SA_CTL_MAGNETIC_DRIVER + println(" (E-Magnetic-Driver):") + elseif type == SA_CTL_PIEZO_SCANNER_DRIVER + println(" (Piezo-Scanner-Driver):") + else + println() + end + + num = get_property_i32(dHandle, i, SA_CTL_PKEY_NUMBER_OF_BUS_MODULE_CHANNELS) + println(" Number of Bus Module Channels: $num") + state = get_property_i32(dHandle, i, SA_CTL_PKEY_MODULE_STATE) + print(" Sensor Module present: ") + println((state & SA_CTL_MOD_STATE_BIT_SM_PRESENT) != 0 ? "yes" : "no") +end + +# ===== Channel info ===== +for i in 0:(noOfChannels - 1) + println(" Channel: $i") + + pos_name = get_property_string(dHandle, i, SA_CTL_PKEY_POSITIONER_TYPE_NAME) + type = get_property_i32(dHandle, i, SA_CTL_PKEY_POSITIONER_TYPE) + + println(" Positioner Type: $pos_name ($type)") + + state = get_property_i32(dHandle, i, SA_CTL_PKEY_CHANNEL_STATE) + + print(" Amplifier enabled: ") + println((state & SA_CTL_CH_STATE_BIT_AMPLIFIER_ENABLED) != 0 ? "yes" : "no") + + # Channel type-specific info + ch_type = get_property_i32(dHandle, i, SA_CTL_PKEY_CHANNEL_TYPE) + + if ch_type == SA_CTL_STICK_SLIP_PIEZO_DRIVER + maxCLF = get_property_i32(dHandle, i, SA_CTL_PKEY_MAX_CL_FREQUENCY) + + println(" Max-CLF: $maxCLF Hz") + + elseif ch_type == SA_CTL_MAGNETIC_DRIVER + print(" Channel is phased: ") + println((state & SA_CTL_CH_STATE_BIT_IS_PHASED) != 0 ? "yes" : "no") + end + + println("-------------------------------------------------------") +end + + +# reference the stage +function set_property_i32(dHandle, idx, pkey, value) + errcode = SA_CTL_SetProperty_i32(dHandle, idx, pkey, value) + + error_check!(errcode, msg="SetProperty failed (pkey=$pkey, idx=$idx, value=$value)") +end + +function set_property_i64(dHandle, idx, pkey, value) + errcode = SA_CTL_SetProperty_i64(dHandle, idx, pkey, value) + error_check!(errcode, msg="SetProperty_i64 failed (pkey=$pkey, idx=$idx)") +end + +X_channel = 0 +Y_channel = 1 + +for channel in (X_channel, Y_channel) + #Set to closed-loop movement + set_property_i32(dHandle, channel, SA_CTL_PKEY_MOVE_MODE, SA_CTL_MOVE_MODE_CL_ABSOLUTE) + + #Set max closed loop frequency (maxCLF) to 18.5 kHz. Vendor software uses 18.5 kHz as default. + set_property_i32(dHandle, channel, SA_CTL_PKEY_MAX_CL_FREQUENCY, 18500) + + #set the hold time to infinite ms. Infinte hold time to prevent drift when the stage is not moving. + set_property_i32(dHandle, channel, SA_CTL_PKEY_HOLD_TIME, SA_CTL_HOLD_TIME_INFINITE) + + # Set velocity to 1 mm/s + set_property_i64(dHandle, channel, SA_CTL_PKEY_MOVE_VELOCITY, 1_000_000_000) + + #Set acceleration to 1 mm/s2 + set_property_i64(dHandle, channel, SA_CTL_PKEY_MOVE_ACCELERATION, 1_000_000_000) + +end + +for ch in (X_channel, Y_channel) + #Check if both channels are in closed-loop mode + mode = get_property_i32(dHandle, ch, SA_CTL_PKEY_MOVE_MODE) + println("Channel $ch move mode = $mode") + +end + +function findReference(dHandle, channel) + println("MCS2 find reference on channel: $channel.") + set_property_i32(dHandle, channel, SA_CTL_PKEY_REFERENCING_OPTIONS, 2) + + errcode = SA_CTL_Reference(dHandle, channel, 0) + + error_check!(errcode, msg="Failed to start referencing on channel $channel") + println("Referencing started.") +end + +function wait_for_referencing(dHandle, channel) + println("Waiting for referencing to complete on channel $channel...") + + t0 = time() + + while true + # Read channel state + state = get_property_i32(dHandle, channel, SA_CTL_PKEY_CHANNEL_STATE) + + # Check referencing bit + is_referencing = (state & SA_CTL_CH_STATE_BIT_REFERENCING) != 0 + + if !is_referencing + + # Check if referenced + referenced = (state & SA_CTL_CH_STATE_BIT_IS_REFERENCED) !=0 + + if !referenced + error("Referencing failed on channel $channel") + end + + println("Channel $channel referenced.") + return + end + + sleep(0.1) # avoid busy-waiting (100 ms) + end +end + +function reference_all(dHandle) + + for channel in (X_channel, Y_channel) + findReference(dHandle, channel) + end + + for channel in (X_channel, Y_channel) + wait_for_referencing(dHandle, channel) + end + +end + +# Check for any physical position offset from (0, 0) +x_offset = get_property_i64(dHandle, X_channel, SA_CTL_PKEY_LOGICAL_SCALE_OFFSET) +y_offset = get_property_i64(dHandle, Y_channel, SA_CTL_PKEY_LOGICAL_SCALE_OFFSET) +println("X logical scale offset: $(x_offset) pm") +println("Y logical scale offset: $(y_offset) pm") + +reference_all(dHandle) + +#get position +function get_position(dHandle, channel) + value = Ref{Int64}() + + err = SA_CTL_GetProperty_i64(dHandle, channel, SA_CTL_PKEY_POSITION, value, Ref{Csize_t}(1)) + + error_check!(err) + + return value[] +end + +function wait_for_move(dHandle, channel; timeout_s=60.0) + t0 = time() + while true + state = get_property_i32(dHandle, channel, SA_CTL_PKEY_CHANNEL_STATE) + moving = (state & SA_CTL_CH_STATE_BIT_ACTIVELY_MOVING) != 0 + moving || break + if time() - t0 > timeout_s + SA_CTL_Stop(dHandle, channel, 0) + error("Channel $channel: move timeout after $(timeout_s)s") + end + sleep(0.05) + end +end + +function _drive_to_endstop(dHandle, channel, target_pm; timeout_s=60.0) + set_property_i32(dHandle, channel, SA_CTL_PKEY_MOVE_MODE, SA_CTL_MOVE_MODE_CL_ABSOLUTE) + + errcode = SA_CTL_Move(dHandle, channel, target_pm, 0) + error_check!(errcode, msg="Move command failed on channel $channel") + + wait_for_move(dHandle, channel; timeout_s=timeout_s) + + SA_CTL_Stop(dHandle, channel, 0) +end + +function find_travel_range(dHandle, channel; overshoot_pm=Int64(70e9), timeout_s=60.0) + println("Channel $channel: driving to negative end stop ...") + _drive_to_endstop(dHandle, channel, -overshoot_pm; timeout_s=timeout_s) + min_pos = get_position(dHandle, channel) + println(" Negative end stop at $(min_pos/1e6) µm") + + println("Channel $channel: driving to positive end stop ...") + _drive_to_endstop(dHandle, channel, overshoot_pm; timeout_s=timeout_s) + max_pos = get_position(dHandle, channel) + println(" Positive end stop at $(max_pos/1e6) µm") + + range_mm = (max_pos - min_pos) / 1e9 + println("Channel $channel: physical travel range ≈ $(range_mm) mm") + + return min_pos, max_pos +end + +function find_xy_travel_range(dHandle) + p_x_min, p_x_max = find_travel_range(dHandle, X_channel) + p_y_min, p_y_max = find_travel_range(dHandle, Y_channel) + return (p_x_min, p_x_max, p_y_min, p_y_max) +end + +function get_xy_position(dHandle) + + x = get_position(dHandle, X_channel) + y = get_position(dHandle, Y_channel) + + return x, y +end + +# println(get_position(dHandle, channel), "pm") +x, y = get_xy_position(dHandle) +println("X = $(x/1e6) µm") +println("Y = $(y/1e6) µm") + +#get travel limit/range +function get_travel_range(dHandle, channel) + + min_pos = get_property_i64(dHandle, channel, SA_CTL_PKEY_RANGE_LIMIT_MIN) + max_pos = get_property_i64(dHandle, channel, SA_CTL_PKEY_RANGE_LIMIT_MAX) + + return min_pos, max_pos +end + +#for both channels +function get_xy_travel_range(dHandle) + + x_min, x_max = get_travel_range(dHandle, X_channel) + y_min, y_max = get_travel_range(dHandle, Y_channel) + + return (x_min, x_max, y_min, y_max) +end + +function set_travel_range(dHandle, channel, min_pm::Int64, max_pm::Int64) + + set_property_i64(dHandle, channel, SA_CTL_PKEY_RANGE_LIMIT_MIN, min_pm) + set_property_i64(dHandle, channel, SA_CTL_PKEY_RANGE_LIMIT_MAX, max_pm) + + # Read back to confirm what device actually stored + actual_min = get_property_i64(dHandle, channel, SA_CTL_PKEY_RANGE_LIMIT_MIN) + actual_max = get_property_i64(dHandle, channel, SA_CTL_PKEY_RANGE_LIMIT_MAX) + + return actual_min, actual_max +end + +function set_xy_travel_range(dHandle, min_pm::Int64, max_pm::Int64) + + x_min, x_max = set_travel_range(dHandle, X_channel, min_pm, max_pm) + y_min, y_max = set_travel_range(dHandle, Y_channel, min_pm, max_pm) + + return (x_min, x_max, y_min, y_max) +end + +# Physical travel range — drives the stage to each mechanical end stop +p_x_min, p_x_max, p_y_min, p_y_max = find_xy_travel_range(dHandle) +println("Physical travel range — X: $(p_x_min/1e6) to $(p_x_max/1e6) µm (≈$((p_x_max-p_x_min)/1e9) mm)") +println("Physical travel range — Y: $(p_y_min/1e6) to $(p_y_max/1e6) µm (≈$((p_y_max-p_y_min)/1e9) mm)") + +# Set software travel range limits +min_position_pm = Int64(-20e9) +max_position_pm = Int64(20e9) + +# Software range limits (0/0 by default — these are configurable limits, not the physical range) +s_x_min, s_x_max, s_y_min, s_y_max = set_xy_travel_range(dHandle, min_position_pm,max_position_pm) +println("Software travel range - X: $(s_x_min/1e6) to $(s_x_max/1e6) µm" ) +println("Software travel range - Y: $(s_y_min/1e6) to $(s_y_max/1e6) µm" ) + +# move the stage +function move_abs(dHandle, channel, moveValue) + println("Starting move on channel $channel to position $moveValue...") + + errcode = SA_CTL_Move(dHandle, channel, moveValue, 0) + + error_check!(errcode, msg="Move command failed") + + println("Move started (non-blocking).") +end + +function move_xy(dHandle, x_target, y_target) + + move_abs(dHandle, X_channel, x_target) + + move_abs(dHandle,Y_channel,y_target) + + wait_for_move(dHandle, X_channel) + + wait_for_move(dHandle,Y_channel) + +end + +move_xy(dHandle, Int64(100e6), Int64(-50e6)) + +# Check if the move was successful +x, y = get_xy_position(dHandle) +println("X=$(x/1e6) µm, " * "Y=$(y/1e6) µm") + +function stop(dHandle, channel) + println("MCS2 stop channel: $channel.") + + errcode = SA_CTL_Stop(dHandle, channel, 0) + + error_check!(errcode, msg="Failed to stop channel $channel") +end + +stop(dHandle, X_channel) +stop(dHandle, Y_channel) + +errcode = SA_CTL_Close(dHandle) +error_check!(errcode, msg="Failed to close device") + + diff --git a/src/hardware_implementations/smaract_stage/types_smaract.jl b/src/hardware_implementations/smaract_stage/types_smaract.jl new file mode 100644 index 0000000..4c01414 --- /dev/null +++ b/src/hardware_implementations/smaract_stage/types_smaract.jl @@ -0,0 +1,88 @@ + +mutable struct MCS2Stage <: Stage + stagelabel :: String + n_channels :: Int + channel_ids :: Vector{Int32} + connectionstatus :: Bool + dHandle :: Ref{SA_CTL_DeviceHandle_t} + servostatus :: Vector{Bool} + + pos_pm :: Vector{Int64} # picometres + min_pm :: Vector{Int64} + max_pm :: Vector{Int64} + home_pm :: Vector{Int64} + + velocity_pm_s :: Vector{Int64} # pm/s (1 mm/s = 1_000_000_000) + accel_pm_s2 :: Vector{Int64} # pm/s² + + is_calibrated :: Vector{Bool} + is_referenced :: Vector{Bool} + connected :: Vector{Bool} # true = positioner attached & usable + + dimensions :: Int + real_x :: Float64 + real_y :: Float64 + real_z :: Float64 + targ_x :: Float64 + targ_y :: Float64 + targ_z :: Float64 + range_x :: Tuple{Float64, Float64} + range_y :: Tuple{Float64, Float64} + range_z :: Tuple{Float64, Float64} +end + +""" + MCS2Stage(; kwargs...) -> MCS2Stage + +Keyword-argument constructor with safe defaults for a 3-channel MCS2. +All positions default to 0; call `initialize!(stage)` to populate them +from the device. +""" +function MCS2Stage(; + stagelabel :: String = "SmarAct MCS2", + n_channels :: Int = 3, + channel_ids :: Vector{Int32} = Int32[0, 1, 2], + connectionstatus :: Bool = false, + dHandle :: Ref{SA_CTL_DeviceHandle_t} = Ref{SA_CTL_DeviceHandle_t}(0), + servostatus :: Vector{Bool} = fill(false, 3), + + pos_pm :: Vector{Int64} = zeros(Int64, 3), + min_pm :: Vector{Int64} = fill(Int64(-10_000_000_000), 3), # –10 mm + max_pm :: Vector{Int64} = fill(Int64( 10_000_000_000), 3), # +10 mm + home_pm :: Vector{Int64} = zeros(Int64, 3), + + velocity_pm_s :: Vector{Int64} = fill(Int64(1_000_000_000), 3), # 1 mm/s + accel_pm_s2 :: Vector{Int64} = fill(Int64(1_000_000_000), 3), # 1 mm/s² + + is_calibrated :: Vector{Bool} = fill(false, 3), + is_referenced :: Vector{Bool} = fill(false, 3), + connected :: Vector{Bool} = fill(true, 3), + dimensions :: Union{Int, Nothing} = nothing, + + real_x :: Float64 = 0.0, + real_y :: Float64 = 0.0, + real_z :: Float64 = 0.0, + targ_x :: Float64 = 0.0, + targ_y :: Float64 = 0.0, + targ_z :: Float64 = 0.0, + range_x :: Union{Tuple{Float64,Float64}, Nothing} = nothing, + range_y :: Union{Tuple{Float64,Float64}, Nothing} = nothing, + range_z :: Union{Tuple{Float64,Float64}, Nothing} = nothing) + + dims = dimensions === nothing ? min(n_channels, 3) : dimensions + + rx = range_x === nothing ? (min_pm[1] / 1e6, max_pm[1] / 1e6) : range_x + ry = range_y === nothing ? (min_pm[2] / 1e6, max_pm[2] / 1e6) : range_y + rz = if range_z !== nothing + range_z + elseif n_channels >= 3 + (min_pm[3] / 1e6, max_pm[3] / 1e6) + else + (0.0, 0.0) + end + + return MCS2Stage( + stagelabel, n_channels, channel_ids, connectionstatus, dHandle, servostatus, pos_pm, min_pm, max_pm, home_pm, velocity_pm_s, accel_pm_s2, + is_calibrated, is_referenced, connected, dims, real_x, real_y, real_z, targ_x, targ_y, targ_z, rx, ry, rz + ) +end diff --git a/src/hardware_implementations/xem_dac/XEM_DAC.jl b/src/hardware_implementations/xem_dac/XEM_DAC.jl new file mode 100644 index 0000000..b2bf07b --- /dev/null +++ b/src/hardware_implementations/xem_dac/XEM_DAC.jl @@ -0,0 +1,20 @@ + +module XEM_DAC + + + + using ...MicroscopeControl.HardwareImplementations.OK_XEM + + import ...MicroscopeControl.HardwareImplementations.OK_XEM: setwirein, activetriggerin + import ...MicroscopeControl: export_state, initialize, shutdown + + const okFP = "C:\\Program Files\\Opal Kelly\\FrontPanelUSB\\API\\lib\\x64\\okFrontPanel.dll" + + + include("types.jl") + include("interface_methods.jl") + + export XEM_dac, start, stop, setvoltageA, setvoltageB, setvoltageC, setvoltageD, setvoltageAll + #export setvoltage, start, stop #, initialize + +end \ No newline at end of file diff --git a/src/hardware_implementations/xem_dac/interface_methods.jl b/src/hardware_implementations/xem_dac/interface_methods.jl new file mode 100644 index 0000000..73982ee --- /dev/null +++ b/src/hardware_implementations/xem_dac/interface_methods.jl @@ -0,0 +1,146 @@ +const EP_WIREIN_A = 0x01 +const EP_WIREIN_B = 0x02 +const EP_WIREIN_C = 0x03 +const EP_WIREIN_D = 0x04 + +const EP_WIREIN_START = 0x05 +const BIT_START = 0x00000001 +const BIT_STOP = 0x00000000 + + +# Voltage-to-code helper (adjust for DAC8814 mode) +""" + volts_to_code(v::Float64; vmin::Float64=-10.0, vmax::Float64=10.0) +Convert a voltage value to hex code for the DAC8814. +# Arguments +- `v::Float64`: The voltage value to convert (in volts). +- `vmin::Float64`: The minimum voltage the DAC can output (default: -10.0 V). +- `vmax::Float64`: The maximum voltage the DAC can output (default: 10.0 V). +# Returns +- `UInt32`: The corresponding hex code. +""" +function volts_to_code(v::Float64; vmin::Float64=-10.0, vmax::Float64=10.0) + if v < vmin || v > vmax + error("Voltage $v V out of range for Vmin=$vmin V and Vmax=$vmax V") + end + return UInt32(round(65535 - ((v - vmin) / (vmax - vmin)) * 65535)) +end + +# send voltages to FPGA +""" + setvoltageAll(fpga::XEM_dac, va::Float64, vb::Float64, vc::Float64, vd::Float64) +Set the output voltages for all four channels of the DAC. +# Arguments +- `fpga::XEM_dac`: An instance of the XEM_dac hardware implementation. +- `va::Float64`: The desired output voltage for channel A (in volts). +- `vb::Float64`: The desired output voltage for channel B (in volts). +- `vc::Float64`: The desired output voltage for channel C (in volts). +- `vd::Float64`: The desired output voltage for channel D (in volts). + +""" +function setvoltageAll(fpga::XEM_dac, va::Float64, vb::Float64, vc::Float64, vd::Float64) + a = volts_to_code(va) + b = volts_to_code(vb) + c = volts_to_code(vc) + d = volts_to_code(vd) + + setwirein(fpga.xem, EP_WIREIN_A, a) + setwirein(fpga.xem, EP_WIREIN_B, b) + setwirein(fpga.xem, EP_WIREIN_C, c) + setwirein(fpga.xem, EP_WIREIN_D, d) + + return nothing +end + + +""" + setvoltageA(fpga::XEM_dac, va::Float64) +Set the output voltage for channel A of the DAC. +# Arguments +- `fpga::XEM_dac`: An instance of the XEM_dac hardware implementation. +- `va::Float64`: The desired output voltage for channel A (in volts). + +""" +function setvoltageA(fpga::XEM_dac, va::Float64) + a = volts_to_code(va) + + setwirein(fpga.xem, EP_WIREIN_A, a) + + return nothing +end + +# set voltage for channel B +""" + setvoltageB(fpga::XEM_dac, vb::Float64) +Set the output voltage for channel B of the DAC. +# Arguments +- `fpga::XEM_dac`: An instance of the XEM_dac hardware implementation. +- `vb::Float64`: The desired output voltage for channel B (in volts). + +""" +function setvoltageB(fpga::XEM_dac, vb::Float64) + b = volts_to_code(vb) + + setwirein(fpga.xem, EP_WIREIN_B, b) + + return nothing +end + +# set voltage for channel C +""" + setvoltageC(fpga::XEM_dac, vc::Float64) +Set the output voltage for channel C of the DAC. +# Arguments +- `fpga::XEM_dac`: An instance of the XEM_dac hardware implementation. +- `vc::Float64`: The desired output voltage for channel C (in volts). + +""" +function setvoltageC(fpga::XEM_dac, vc::Float64) + c = volts_to_code(vc) + + setwirein(fpga.xem, EP_WIREIN_C, c) + + return nothing +end + +# set voltage for channel D +""" + setvoltageD(fpga::XEM_dac, vd::Float64) +Set the output voltage for channel D of the DAC. +# Arguments +- `fpga::XEM_dac`: An instance of the XEM_dac hardware +- `vd::Float64`: The desired output voltage for channel D (in volts). + +""" +function setvoltageD(fpga::XEM_dac, vd::Float64) + d = volts_to_code(vd) + + setwirein(fpga.xem, EP_WIREIN_D, d) + + return nothing +end + +# start DAC output +""" + start(fpga::XEM_dac) +Start the DAC output on the FPGA. +# Arguments +- `fpga::XEM_dac`: An instance of the XEM_dac hardware implementation. + +""" +function start(fpga::XEM_dac) + setwirein(fpga.xem, EP_WIREIN_START, BIT_START) + return nothing +end + +""" + stop(fpga::XEM_dac) +Stop the DAC output on the FPGA. +# Arguments +- `fpga::XEM_dac`: An instance of the XEM_dac hardware +""" +function stop(fpga::XEM_dac) + setwirein(fpga.xem, EP_WIREIN_START, BIT_STOP) + return nothing +end + diff --git a/src/hardware_implementations/xem_dac/types.jl b/src/hardware_implementations/xem_dac/types.jl new file mode 100644 index 0000000..1dd504d --- /dev/null +++ b/src/hardware_implementations/xem_dac/types.jl @@ -0,0 +1,15 @@ + + +mutable struct XEM_dac + xem::XEM + +end + + +function XEM_dac(; + xem::XEM=XEM()) + + return XEM_dac(xem) + +end +