Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix LDI laser engine errors caused by IlluminationController #86

Merged
merged 3 commits into from
Feb 3, 2025
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
51 changes: 14 additions & 37 deletions software/control/celesta.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
from squid.abc import LightSource
from control.microscope import LightSourceType, IntensityControlMode, ShutterControlMode

import squid.logging

log = squid.logging.get_logger(__name__)


def lumencor_httpcommand(command="GET IP", ip="192.168.201.200"):
"""
Expand Down Expand Up @@ -43,9 +47,9 @@ def __init__(self, **kwds):
self.n_lasers = self.get_number_lasers()
self.live = True
except:
print(traceback.format_exc())
log.error(traceback.format_exc())
self.live = False
print("Failed to connect to Lumencor Laser at ip:", ip)
log.error("Failed to connect to Lumencor Laser at ip:", ip)

if self.live:
[self.pmin, self.pmax] = self.get_intensity_range()
Expand Down Expand Up @@ -89,17 +93,14 @@ def get_color(self, laser_id):
"""Returns the color of the current laser"""
self.message = lumencor_httpcommand(command="GET CHMAP", ip=self.ip)
colors = self.message["message"].split(" ")[2:]
print(colors)
log.info(colors)
return colors[int(laser_id)]

def get_IP(self):
self.message = lumencor_httpcommand(command="GET IP", ip=self.ip)
return self.message

def get_shutter_control_mode(self):
"""
Return True/False the lasers can be controlled with TTL.
"""
self.message = lumencor_httpcommand(command="GET TTLENABLE", ip=self.ip)
response = self.message["message"]
if response[-1] == "1":
Expand All @@ -108,63 +109,45 @@ def get_shutter_control_mode(self):
return ShutterControlMode.Software

def set_shutter_control_mode(self, mode):
"""
Turn on/off external TTL control mode.
"""
if mode == ShutterControlMode.TTL:
ttl_enable = "1"
else:
ttl_enable = "0"
self.message = lumencor_httpcommand(command="SET TTLENABLE " + ttl_enable, ip=self.ip)

def get_shutter_state(self, laser_id):
"""
Return True/False the laser is on/off.
"""
self.message = lumencor_httpcommand(command="GET CH " + str(laser_id), ip=self.ip)
response = self.message["message"]
self.on = response[-1] == "1"
return self.on

def get_intensity_range(self):
"""
Return [minimum power, maximum power].
"""
max_int = 1000 # default
self.message = lumencor_httpcommand(command="GET MAXINT", ip=self.ip)
if self.message["message"][0] == "A":
max_int = float(self.message["message"].split(" ")[-1])
return [0, max_int]

def get_intensity(self, laser_id):
"""
Return the current laser power.
"""
self.message = lumencor_httpcommand(command="GET CHINT " + str(laser_id), ip=self.ip)
# print(command = 'GET CHINT '+str(laser_id), ip=self.ip)
log.debug(command = 'GET CHINT '+str(laser_id), ip=self.ip)
response = self.message["message"]
power = float(response.split(" ")[-1])
return power
intensity = power / self.pmax * 100
return intensity

def set_shutter_state(self, laser_id, on):
"""
Turn the laser on/off.
"""
if on:
self.message = lumencor_httpcommand(command="SET CH " + str(laser_id) + " 1", ip=self.ip)
self.on = True
else:
self.message = lumencor_httpcommand(command="SET CH " + str(laser_id) + " 0", ip=self.ip)
self.on = False
print("Turning On/Off", self.on, self.message)
log.info("Turning On/Off", self.on, self.message)

def set_intensity(self, laser_id, power_in_mw):
"""
power_in_mw - The desired laser power in mW.
"""
print("Setting Power", power_in_mw, self.message)
if power_in_mw > self.pmax:
power_in_mw = self.pmax
def set_intensity(self, laser_id, intensity):
log.info("Setting intensity to ", intensity)
power_in_mw = self.pmax * intensity / 100
self.message = lumencor_httpcommand(
command="SET CHINT " + str(laser_id) + " " + str(int(power_in_mw)), ip=self.ip
)
Expand All @@ -173,18 +156,12 @@ def set_intensity(self, laser_id, power_in_mw):
return False

def shut_down(self):
"""
Turn the laser off.
"""
if self.live:
for i in range(self.n_lasers):
self.set_intensity(i, 0)
self.set_shutter_state(i, False)

def get_status(self):
"""
Get the status
"""
return self.live


Expand Down
3 changes: 0 additions & 3 deletions software/control/core/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -522,9 +522,6 @@ def __init__(

self.enable_channel_auto_filter_switching = True

if USE_LDI_SERIAL_CONTROL:
self.ldi = self.microscope.ldi

if SUPPORT_SCIMICROSCOPY_LED_ARRAY:
# to do: add error handling
self.led_array = serial_peripherals.SciMicroscopyLEDArray(
Expand Down
6 changes: 3 additions & 3 deletions software/control/gui_hcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import squid.config
import squid.stage.utils
import control.microscope
from control.microscope import LightSourceType, IntensityControlMode, ShutterControlMode
from control.microscope import LightSourceType, IntensityControlMode, ShutterControlMode, IlluminationController

log = squid.logging.get_logger(__name__)

Expand Down Expand Up @@ -371,7 +371,7 @@ def loadHardwareObjects(self):
if USE_LDI_SERIAL_CONTROL:
try:
self.ldi = serial_peripherals.LDI()
self.illuminationController = control.microscope.IlluminationController(
self.illuminationController = IlluminationController(
self.microcontroller, self.ldi.intensity_mode, self.ldi.shutter_mode, LightSourceType.LDI, self.ldi
)
except Exception:
Expand All @@ -383,7 +383,7 @@ def loadHardwareObjects(self):
import control.celesta

self.celesta = control.celesta.CELESTA()
self.illuminationController = control.microscope.IlluminationController(
self.illuminationController = IlluminationController(
self.microcontroller,
IntensityControlMode.Software,
ShutterControlMode.TTL,
Expand Down
13 changes: 2 additions & 11 deletions software/control/microscope.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,6 @@ def __init__(
self.channel_mappings_software = {}
self.is_on = {}
self.intensity_settings = {}
self.pmin, self.pmax = 0, 1000
self.current_channel = None

if self.light_source_type is not None:
Expand All @@ -224,7 +223,6 @@ def configure_light_source(self):
self.set_intensity_control_mode(self.intensity_control_mode)
self.set_shutter_control_mode(self.shutter_control_mode)
self.channel_mappings_software = self.light_source.channel_mappings
self.get_intensity_range()
for ch in self.channel_mappings_software:
self.intensity_settings[ch] = self.get_intensity(ch)
self.is_on[ch] = self.light_source.get_shutter_state(self.channel_mappings_software[ch])
Expand All @@ -249,14 +247,9 @@ def get_shutter_control_mode(self):
self.shutter_control_mode = mode
return mode

def get_intensity_range(self, channel=None):
if self.intensity_control_mode == IntensityControlMode.Software:
[self.pmin, self.pmax] = self.light_source.get_intensity_range()

def get_intensity(self, channel):
if self.intensity_control_mode == IntensityControlMode.Software:
power = self.light_source.get_intensity(self.channel_mappings_software[channel])
intensity = power / self.pmax * 100
intensity = self.light_source.get_intensity(self.channel_mappings_software[channel])
self.intensity_settings[channel] = intensity
return intensity # 0 - 100

Expand All @@ -267,7 +260,6 @@ def turn_on_illumination(self, channel=None):
if self.shutter_control_mode == ShutterControlMode.Software:
self.light_source.set_shutter_state(self.channel_mappings_software[channel], on=True)
elif self.shutter_control_mode == ShutterControlMode.TTL:
print("TTL!!")
# self.microcontroller.set_illumination(self.channel_mappings_TTL[channel], self.intensity_settings[channel])
self.microcontroller.turn_on_illumination()

Expand All @@ -290,8 +282,7 @@ def set_current_channel(self, channel):
def set_intensity(self, channel, intensity):
if self.intensity_control_mode == IntensityControlMode.Software:
if intensity != self.intensity_settings[channel]:
power = intensity / 100 * self.pmax
self.light_source.set_intensity(self.channel_mappings_software[channel], power)
self.light_source.set_intensity(self.channel_mappings_software[channel], intensity)
self.intensity_settings[channel] = intensity
self.microcontroller.set_illumination(self.channel_mappings_TTL[channel], intensity)

Expand Down
60 changes: 37 additions & 23 deletions software/control/serial_peripherals.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import time
from typing import Tuple, Optional
import struct
from control.microscope import LightSourceType, IntensityControlMode, ShutterControlMode
from control._def import *
from squid.abc import LightSource

import squid.logging
Expand Down Expand Up @@ -430,6 +432,7 @@ def __init__(self, SN="00000001"):
735: 730,
750: 730,
}
self.active_channel = None

def initialize(self):
self.serial_connection.write_and_check("run!\r", "ok")
Expand Down Expand Up @@ -459,33 +462,48 @@ def set_intensity(self, channel, intensity):
intensity = "{:.2f}".format(intensity)
self.log.debug("set:" + channel + "=" + intensity + "\r")
self.serial_connection.write_and_check("set:" + channel + "=" + intensity + "\r", "ok")
self.log.debug("active channel: " + str(self.active_channel))

def get_intensity(self, channel):
return 0 # To be implemented

def get_intensity_range(self):
return [0, 100]

def set_shutter_state(self, channel, state):
try:
response = self.serial_connection.write_and_read("set?\r")
pairs = response.replace('SET:', '').split(',')
intensities = {}
for pair in pairs:
channel, value = pair.split('=')
intensities[int(channel)] = int(value)
return intensity[channel]
except:
return None

def set_shutter_state(self, channel, on):
channel = str(channel)
state = str(state)
state = str(on)
if self.active_channel is not None and channel != self.active_channel:
self.set_active_channel_shutter(False)
self.serial_connection.write_and_check("shutter:" + channel + "=" + state + "\r", "ok")
if on:
self.active_channel = channel

def get_shutter_state(self, channel):
self.serial_connection.write_and_check("shutter?\r", "")
return 0 # To be implemented

def set_active_channel(self, channel):
self.active_channel = channel
self.log.debug("[set active channel to " + str(channel) + "]")
try:
response = self.serial_connection.write_and_read("shutter?" + channel + "\r")
state = response.split('=')[1]
return 1 if state == 'OPEN' else 0
except:
return None

def set_active_channel_shutter(self, state):
channel = str(self.active_channel)
state = str(state)
self.log.debug("shutter:" + channel + "=" + state + "\r")
self.serial_connection.write_and_check("shutter:" + channel + "=" + state + "\r", "ok")

def shut_down(self):
for ch in list(set(self.channel_mappings.values())):
self.set_intensity(ch, 0)
self.set_shutter_state(ch, False)
self.serial_connection.close()


class LDI_Simulation(LightSource):
"""Wrapper for communicating with LDI over serial"""
Expand Down Expand Up @@ -539,25 +557,21 @@ def set_intensity(self, channel, intensity):
def get_intensity(self, channel):
return 0

def get_intensity_range(self):
return [0, 100]

def set_shutter_state(self, channel, state):
def set_shutter_state(self, channel, on):
channel = str(channel)
state = str(state)
state = str(on)

def get_shutter_state(self, channel):
return 0

def set_active_channel(self, channel):
self.active_channel = channel
self.log.debug("[set active channel to " + str(channel) + "]")

def set_active_channel_shutter(self, state):
channel = str(self.active_channel)
state = str(state)
self.log.debug("shutter:" + channel + "=" + state + "\r")

def shut_down(self):
pass


class SciMicroscopyLEDArray:
"""Wrapper for communicating with SciMicroscopy over serial"""
Expand Down
10 changes: 0 additions & 10 deletions software/squid/abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,16 +106,6 @@ def get_intensity(self, channel) -> float:
"""
pass

@abstractmethod
def get_intensity_range(self) -> Tuple[float, float]:
"""
Get the valid intensity range.

Returns:
Tuple[float, float]: (minimum intensity, maximum intensity)
"""
pass

@abstractmethod
def shut_down(self):
"""Safely shut down the light source."""
Expand Down
Loading