BioImager  3.9.1
A .NET microscopy imaging library. Supports various microscopes by using imported libraries & GUI automation. Supported libraries include PriorĀ® & ZeissĀ® & all devices supported by Micromanager 2.0 and python-microscope.
Loading...
Searching...
No Matches
deepstar.py
1#!/usr/bin/env python3
2
3## Copyright (C) 2020 David Miguel Susano Pinto <carandraug@gmail.com>
4## Copyright (C) 2020 Mick Phillips <mick.phillips@gmail.com>
5##
6## This file is part of Microscope.
7##
8## Microscope is free software: you can redistribute it and/or modify
9## it under the terms of the GNU General Public License as published by
10## the Free Software Foundation, either version 3 of the License, or
11## (at your option) any later version.
12##
13## Microscope is distributed in the hope that it will be useful,
14## but WITHOUT ANY WARRANTY; without even the implied warranty of
15## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16## GNU General Public License for more details.
17##
18## You should have received a copy of the GNU General Public License
19## along with Microscope. If not, see <http://www.gnu.org/licenses/>.
20
21import logging
22
23import serial
24
25import microscope
26import microscope.abc
27
28
29_logger = logging.getLogger(__name__)
30
31
34):
35 """Omicron DeepStar laser.
36
37 Omicron LDM lasers can be bought with and without the LDM.APC
38 power monitoring option (light pick-off). If this option is not
39 available, the `power` attribute will return the set power value
40 instead of the actual power value.
41
42 """
43
44 def __init__(self, com, baud=9600, timeout=2.0, **kwargs):
45 super().__init__(**kwargs)
46 self.connectionconnection = serial.Serial(
47 port=com,
48 baudrate=baud,
49 timeout=timeout,
50 stopbits=serial.STOPBITS_ONE,
51 bytesize=serial.EIGHTBITS,
52 parity=serial.PARITY_NONE,
53 )
54 # If the laser is currently on, then we need to use 7-byte mode; otherwise we need to
55 # use 16-byte mode.
56 self._write_write(b"S?")
57 response = self._readline()
58 _logger.info("Current laser state: [%s]", response.decode())
59
60 self._write_write(b"STAT3")
61 option_codes = self._readline()
62 if not option_codes.startswith(b"OC "):
64 "Failed to get option codes '%s'" % option_codes.decode()
65 )
66 if option_codes[9:12] == b"AP1":
67 self._has_apc = True
68 else:
69 _logger.warning(
70 "Laser is missing APC option. Will return set"
71 " power instead of actual power"
72 )
73 self._has_apc = False
74
75 def _write(self, command):
76 """Send a command."""
77 # We'll need to pad the command out to 16 bytes. There's also
78 # a 7-byte mode but we never need to use it. CR/LF counts
79 # towards the byte limit, hence 14 (16-2)
80 command = command.ljust(14) + b"\r\n"
81 response = self.connectionconnection.write(command)
82 return response
83
84 # Get the status of the laser, by sending the
85 # STAT0, STAT1, STAT2, and STAT3 commands.
86 @microscope.abc.SerialDeviceMixin.lock_comms
87 def get_status(self):
88 result = []
89 for i in range(4):
90 self._write_write(("STAT%d" % i).encode())
91 result.append(self._readline().decode())
92 return result
93
94 # Turn the laser ON. Return True if we succeeded, False otherwise.
95 @microscope.abc.SerialDeviceMixin.lock_comms
96 def _do_enable(self):
97 _logger.info("Turning laser ON.")
98 # Turn on deepstar mode with internal voltage ref
99 # Enable internal peak power
100 # Set MF turns off internal digital and bias modulation
101 # Disable analog modulation to digital modulation
102 for cmd, msg in [
103 (b"LON", "Enable response: [%s]"),
104 (b"L2", "L2 response: [%s]"),
105 (b"IPO", "Enable-internal peak power response: [%s]"),
106 (b"MF", "MF response [%s]"),
107 (b"A2DF", "A2DF response [%s]"),
108 ]:
109 self._write_write(cmd)
110 response = self._readline()
111 _logger.debug(msg, response.decode())
112
113 if not self.get_is_onget_is_on():
114 # Something went wrong.
115 self._write_write(b"S?")
116 response = self._readline()
117 _logger.error(
118 "Failed to turn on. Current status: [%s]", response.decode()
119 )
120 return False
121 return True
122
123 def _do_shutdown(self) -> None:
124 self.disable()
125
126 # Turn the laser OFF.
127 @microscope.abc.SerialDeviceMixin.lock_comms
128 def _do_disable(self):
129 _logger.info("Turning laser OFF.")
130 self._write_write(b"LF")
131 return self._readline().decode()
132
133 # Return True if the laser is currently able to produce light. We assume this is equivalent
134 # to the laser being in S2 mode.
135 @microscope.abc.SerialDeviceMixin.lock_comms
136 def get_is_on(self):
137 self._write_write(b"S?")
138 response = self._readline()
139 _logger.debug("Are we on? [%s]", response.decode())
140 return response == b"S2"
141
142 @microscope.abc.SerialDeviceMixin.lock_comms
143 def _do_set_power(self, power: float) -> None:
144 _logger.debug("level=%d", power)
145 power_int = int(power * 0xFFF)
146 _logger.debug("power=%d", power_int)
147 strPower = "PP%03X" % power_int
148 _logger.debug("power level=%s", strPower)
149 self._write_write(strPower.encode())
150 response = self._readline()
151 _logger.debug("Power response [%s]", response.decode())
152
153 def _do_get_power(self) -> float:
154 if not self.get_is_onget_is_on():
155 return 0.0
156 if self._has_apc:
157 query = b"P"
158 scale = 0xCCC
159 else:
160 query = b"PP"
161 scale = 0xFFF
162
163 self._write_write(query + b"?")
164 answer = self._readline()
165 if not answer.startswith(query):
167 "failed to read power from '%s'" % answer.decode()
168 )
169
170 level = int(answer[len(query) :], 16)
171 return float(level) / float(scale)
172
173 @property
174 def trigger_type(self) -> microscope.TriggerType:
175 return microscope.TriggerType.HIGH
176
177 @property
178 def trigger_mode(self) -> microscope.TriggerMode:
179 return microscope.TriggerMode.BULB
180
182 self, ttype: microscope.TriggerType, tmode: microscope.TriggerMode
183 ) -> None:
184 if ttype is not microscope.TriggerType.HIGH:
186 "the only trigger type supported is 'high'"
187 )
188 if tmode is not microscope.TriggerMode.BULB:
190 "the only trigger mode supported is 'bulb'"
191 )
192
193 def _do_trigger(self) -> None:
195 "trigger does not make sense in trigger mode bulb, only enable"
196 )
None disable(self)
Definition: abc.py:307
bool get_is_on(self)
Definition: abc.py:1212
int _write(self, bytes command)
Definition: abc.py:1020
None set_trigger(self, microscope.TriggerType ttype, microscope.TriggerMode tmode)
Definition: deepstar.py:183