Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ authors = ["klidke@unm.edu"]
version = "1.0.0-DEV"

[deps]
CEnum = "fa961155-64e5-5f13-b03f-caf6b980ea82"
CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0"
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
FFTW = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341"
Expand All @@ -17,6 +18,7 @@ Revise = "295af30f-e4ad-537b-8983-00126c2a3abe"
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"

[compat]
CEnum = "0.5.0"
julia = "1.10"

[extras]
Expand Down
27 changes: 27 additions & 0 deletions dev/test_thorcamdcx.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using Revise
using MicroscopeControl

# Test the saving function of Red Laser
using MicroscopeControl.HardwareImplementations.ThorCamDCx

cam = ThorcamDCXCamera()
initialize(cam)

gui(cam)

cam.exposure_time = 0.01 # s
cam.roi.x_start = 100
cam.roi.y_start = 100
cam.roi.width = 200
cam.roi.height = 300

data = capture(cam);


cam.sequence_length = 10
sequence(cam)
data = getdata(cam);

abort(cam)

shutdown(cam)
3 changes: 2 additions & 1 deletion src/MicroscopeControl.jl
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ using .HardwareImplementations.TransmissionDaqControl
using .HardwareImplementations.CrystaLaserControl
using .HardwareImplementations.VortranLaserControl
using .HardwareImplementations.OK_XEM
using .HardwareImplementations.ThorCamDCx

# # Export all HardwareImplementations modules
# export DCAM4, SimulatedCamera, SimulatedStage, PI, MadCityLabs, PI_N472, ThorCamCSC
Expand All @@ -39,7 +40,7 @@ using .HardwareImplementations.OK_XEM
export save_h5, save_attributes_and_data

# Re-export camera implementations
export SimCamera, DCAM4Camera, ThorCamCSC
export SimCamera, DCAM4Camera, ThorCamCSCCamera, ThorCamDCXCamera
export start_sequence, start_live
export getlastframe, capture, live, sequence, abort, getdata
export setexposuretime, settriggermode, setroi!, setexposuretime!
Expand Down
3 changes: 2 additions & 1 deletion src/hardware_implementations/HardwareImplementations.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@ include("mcl_stage/MadCityLabs.jl")
include("pi_N472/PI_N472.jl")

include("thorcam_csc/ThorCamCSC.jl")
include("thorcam_dcx/ThorCamDCx.jl")
include("simulated_light/SimulatedLight.jl")
include("nidaq/NIDAQcard.jl")
include("tcube_laser/TCubeLaserControl.jl")
include("daq_transmission_light/TransmissionDaqControl.jl")
include("crysta_laser_561/CrystaLaserControl.jl")
include("vortran_laser_488/VortranLaserControl.jl")
include("ok_xem/OK_XEM.jl")

include("meadowlark_slm/Meadowlark.jl")

end
18 changes: 18 additions & 0 deletions src/hardware_implementations/meadowlark_slm/Meadowlark.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
module Meadowlark

using ...MicroscopeControl.HardwareInterfaces.SLMInterface
using GLMakie, Images

import ...MicroscopeControl.HardwareInterfaces.SLMInterface: SLM
import ...MicroscopeControl: export_state, initialize, shutdown

export MLSLM, Pupil, Sequence
export displayimage, displayzernike, displayblaze
export genblazed!, genzernike!

include("types.jl")
include("meadowlark_sdk.jl")
include("meadowlark_dev.jl")
include("gen_patterns.jl")

end
184 changes: 184 additions & 0 deletions src/hardware_implementations/meadowlark_slm/gen_patterns.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@

#TODO: Create blazed pattern for any angle and using MLSLM structure instead of an inputted phase array


function genblazed!(slm::MLSLM, is_vert::Bool=true, period::Int=32; blaze_start::Int=1, blaze_end::Int=-1) #Units are pixels
#Create array of size of SLM
width = slm.width
height = slm.height

#Create array of size of SLM
phase_pattern = zeros(Float64, width, height)

if period == 1
blaze_values = zeros(2)
else
blaze_values = LinRange(1, 0, period) #creates a range from 0 to 1 with the period specified
end

if is_vert
pattern_start::Int = (blaze_start)

if blaze_end < 0. || (blaze_end) > height
blaze_end = height
else
pattern_end::Int = (blaze_end)
end

for j in pattern_start:pattern_end
phase_pattern[:, j] .= blaze_values[(j-1)%period+1]
end
else
pattern_start = (blaze_start)

if blaze_end < 0. || (blaze_end) > width
blaze_end = width
else
pattern_end = (blaze_end)
end

for i in pattern_start:pattern_end
phase_pattern[i, :] .= blaze_values[(i-1)%period+1]
end
end
slm.phase = phase_pattern
end

function genzernike!(slm::MLSLM, radial_order::Int, coefficients::Vector{Float64}, radius::Int, x_center::Int, y_center::Int)
phase_array = zeros(Float64, slm.width, slm.height)

x_zernike = LinRange(-1,1, radius*2)
y_zernike = LinRange(-1,1, radius*2)

zernike_array = [(x^2 + y^2 > 1 ? 0.0 : (zernike_sum(x, y, radial_order, coefficients))) for x in x_zernike, y in y_zernike]

reverse!(zernike_array, dims=2) #Reverses along the x axis, so the pattern is drawn correctly on the SLM

zernike_array = zernike_array .% 2pi #Ranges from -2pi to 2pi

for j in 1:size(zernike_array)[2] #Converts negative phase to positive phase
for i in 1:size(zernike_array)[1]
if zernike_array[i, j] < 0
zernike_array[i, j] = 2pi + zernike_array[i, j]
end
end
end

zernike_array = zernike_array ./ 2pi
#TODO: Handle if radius is too large, only draw area that is on SLM
if x_center - radius < 1 || x_center + radius - 1 > slm.width || y_center - radius < 1 || y_center + radius - 1 > slm.height

if x_center-radius < 1
slm_x_start = 1
zernike_x_start = 2 + radius-x_center
else
slm_x_start = x_center-radius
zernike_x_start = 1
end

if x_center + radius - 1 > slm.width
slm_x_end = slm.width
zernike_x_end = radius * 2 + (slm.width - (x_center + radius - 1))
else
slm_x_end = x_center + radius - 1
zernike_x_end = radius*2
end

if y_center-radius < 1
slm_y_start = 1
zernike_y_start = 2 + radius-y_center
else
slm_y_start = y_center-radius
zernike_y_start = 1
end

if y_center + radius - 1 > slm.height
slm_y_end = slm.height
zernike_y_end = radius * 2 + (slm.height - (y_center + radius - 1))
else
slm_y_end = y_center + radius - 1
zernike_y_end = radius*2
end

println( slm_x_start, " ", slm_x_end)
println( slm_y_start, " ",slm_y_end)
println( zernike_x_start, " ", zernike_x_end)
println( zernike_y_start, " ",zernike_y_end)

phase_array[slm_x_start:slm_x_end, slm_y_start:slm_y_end] = zernike_array[zernike_x_start:zernike_x_end, zernike_y_start:zernike_y_end]
else
phase_array[x_center-radius:x_center+radius-1, y_center-radius:y_center+radius-1] = zernike_array[:,:]
end
slm.phase = phase_array
end


#=
This function will use the reccurence reltaions defined in "Efficient and robust recurrence relations for the Zernike circle polynomials and their derivatives in Cartesian coordinates"
It will return an array of values corresponding to the values of a specified number of zernike polynomials.
These are in the order of OSA Zernike polynomials
=#
function zernike_recurs(x, y, order::Int)
number_functions::Int = ((order + 1) * (order + 2)) / 2
zern_polys = Array{Float64,1}(undef, number_functions)
#Value of x and y lies inside unit disk
zern_polys[1] = 1
zern_polys[2] = y
zern_polys[3] = x

if order > 1
#values useful for indexing
cur_indx = 4 #Index in array
ps_indx = 2 #Index for for first polynomial of previous radial power (n-1)
tps_indx = 1 #Index for for first polynomial of second revious radial power (n-2)
for n = 2:order #Note: values of n = 0 and n=1 are given, the rest are calculated using the formulas in the paper
for m = 0:n
if m == 0
zern_polys[cur_indx] = x * zern_polys[ps_indx+(0)] + y * zern_polys[ps_indx+(n-1)]
elseif m == n
zern_polys[cur_indx] = x * zern_polys[ps_indx+(n-1)] - y * zern_polys[ps_indx+(0)]
elseif m == n / 2
zern_polys[cur_indx] = 2 * x * zern_polys[ps_indx+(m)] + 2 * y * zern_polys[ps_indx+(m-1)] - zern_polys[tps_indx+(m-1)]
elseif m == (n - 1) / 2
zern_polys[cur_indx] = y * zern_polys[ps_indx+(n-1-m)] + x * zern_polys[ps_indx+(m-1)] - y * zern_polys[ps_indx+(n-m)] - zern_polys[tps_indx+(m-1)]
elseif m == ((n - 1) / 2) + 1
zern_polys[cur_indx] = x * zern_polys[ps_indx+(m)] + y * zern_polys[ps_indx+(n-1-m)] + x * zern_polys[ps_indx+(m-1)] - zern_polys[tps_indx+(m-1)]
else
zern_polys[cur_indx] = x * zern_polys[ps_indx+(m)] + y * zern_polys[ps_indx+(n-1-m)] + x * zern_polys[ps_indx+(m-1)] - y * zern_polys[ps_indx+(n-m)] - zern_polys[tps_indx+(m-1)]
end
cur_indx += 1
end
tps_indx += n - 1
ps_indx += n
end
end
return zern_polys
end

#=
Given an order of zernike polynomials, calculate an array containing their normalization coefficients
=#
function zernike_norm(order)
#we will use the equation described in the paper to calculate the normalization coefficients
number_functions::Int = ((order + 1) * (order + 2)) / 2
norm_coef = Array{Float64,1}(undef, number_functions)
index = 1
for n = 0:order
for m = 0:n
if n == 2m
norm_coef[index] = sqrt(n + 1)
else
norm_coef[index] = sqrt((2)(n + 1))
end
index += 1
end
end
return norm_coef
end

#=
Sums the value of each zernike polynomial multiplied by their respecitve normilaztion coefficient and weight
=#
function zernike_sum(x, y, order, weights::Vector{Float64})
return sum(zernike_recurs(x, y, order) .* zernike_norm(order) .* weights)
end
22 changes: 22 additions & 0 deletions src/hardware_implementations/meadowlark_slm/interface_functions.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#=
These functions generate images using the write single image function in the Meadowlark SDK
=#

function SLMInterface.displayimage(slm::SLM)
writesingleimage(slm)
end

function SLMInterface.displayimage(slm::SLM, phase::Array{Float64,2})
SLM.phase = phase
return displayimage(slm)
end

function SLMInteface.displayzernike(slm::SLM, zernike::Vector{Float64})
phase = zernike_to_phase(zernike, slm)
return displayimage(slm, phase)
end

function SLMInterface.displayblaze(slm::SLM, is_vert::Bool = false , period::Int = 8; blaze_start::Int=1, blaze_end::Int=1024)
genblazed!(slm, is_vert, period, blaze_start=blaze_start, blaze_end=blaze_end)
return displayimage(slm)
end
39 changes: 39 additions & 0 deletions src/hardware_implementations/meadowlark_slm/meadowlark_dev.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
function loadlut() #TODO: Input LUT path
#This works, now must load the LUT
lut_path = "C:\\Program Files\\Meadowlark Optics\\Blink OverDrive Plus\\LUT Files\\1024x1024_linearVoltage.LUT"
loaded_lut = @ccall "C:\\Program Files\\Meadowlark Optics\\Blink OverDrive Plus\\SDK\\Blink_C_wrapper.dll".Load_LUT_file(1::Cuint, lut_path::Ptr{UInt8})::Cint

end

function writesingleimage(slm::MLSLM)
single_image = slm.phase .* 255 #Converting 0 to 1 to scaled values between 0 and 255
single_image = round.(Int, single_image) #Converting to integers
single_image = convert(Array{UInt8}, single_image)

board_number = 1
wait_for_trigger::Cuint = 0
flip_immediate::Cuint = 0
output_pulse_image_flip::Cuint = 0
output_pulse_image_refresh::Cuint = 0
trigger_timout_ms::Cuint = 5000
image_size::Cint = slm.height * slm.width

#=
single_image = reshape(single_image, 1, image_size)
new_image = zeros(UInt8, image_size) #Issues with Column vs Row major order
new_image[:] .= single_image[1, :]
=#
new_image = reshape(single_image, image_size)
@ccall "C:\\Program Files\\Meadowlark Optics\\Blink OverDrive Plus\\SDK\\Blink_C_wrapper.dll".Write_image(board_number::Cuint,
new_image::Ptr{Cint}, image_size::Cint, wait_for_trigger::Cuint, flip_immediate::Cuint, output_pulse_image_flip::Cuint,
output_pulse_image_refresh::Cuint, trigger_timout_ms::Cuint)::Cint

end

function writesequence(slm::MLSLM)
@error "Not implemented"
end

function selectsequenceimage(slm::MLSLM)
@error "Not implemented"
end
24 changes: 24 additions & 0 deletions src/hardware_implementations/meadowlark_slm/meadowlark_sdk.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
function initializesdk()
# Initialize the SLM
#First Create variables needed to create SDK
bit_depth::Cuint = 12
n_boards_found = Ref{Cuint}(0)
constructed_ok = Ref{Cuint}(1)
is_nematic_type::Cuint = 1
ram_write_enable::Cuint = 1
use_gpu::Cuint = 1
max_transient_frames::Cuint = 10

#Creating the SDK
@ccall "C:\\Program Files\\Meadowlark Optics\\Blink OverDrive Plus\\SDK\\Blink_C_wrapper.dll".Create_SDK(bit_depth::Cuint,
n_boards_found::Ref{Cuint}, constructed_ok::Ref{Cuint}, is_nematic_type::Cuint, ram_write_enable::Cuint, use_gpu::Cuint,
max_transient_frames::Cuint, 0::Cuint)::Cvoid

println(n_boards_found[])
println(constructed_ok[])
end

function closesdk()
# Close the SLM
@ccall "C:\\Program Files\\Meadowlark Optics\\Blink OverDrive Plus\\SDK\\Blink_C_wrapper.dll".Delete_SDK()::Cvoid
end
Loading
Loading