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
cobolt.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
26import microscope.abc
27
28
29_logger = logging.getLogger(__name__)
30
31
36):
37 """Cobolt lasers.
38
39 The cobolt lasers are diode pumped lasers and only supports
40 `TriggerMode.SOFTWARE` (this is probably not completely true, some
41 cobolt lasers are probably not diode pumped and those should be
42 able to support other trigger modes, but we only got access to the
43 04 series).
44
45 """
46
47 def __init__(self, com=None, baud=115200, timeout=0.1, **kwargs):
48 super().__init__(**kwargs)
49 self.connectionconnection = serial.Serial(
50 port=com,
51 baudrate=baud,
52 timeout=timeout,
53 stopbits=serial.STOPBITS_ONE,
54 bytesize=serial.EIGHTBITS,
55 parity=serial.PARITY_NONE,
56 )
57 # Start a logger.
58 response = self.send(b"sn?")
59 _logger.info("Cobolt laser serial number: [%s]", response.decode())
60 # We need to ensure that autostart is disabled so that we can switch emission
61 # on/off remotely.
62 response = self.send(b"@cobas 0")
63 _logger.info("Response to @cobas 0 [%s]", response.decode())
64
65 self._max_power_mw = float(self.send(b"gmlp?"))
66
68
69 def send(self, command):
70 """Send command and retrieve response."""
71 success = False
72 while not success:
73 self._write(command)
74 response = self._readline()
75 # Catch zero-length responses to queries and retry.
76 if not command.endswith(b"?"):
77 success = True
78 elif len(response) > 0:
79 success = True
80 return response
81
82 @microscope.abc.SerialDeviceMixin.lock_comms
83 def clearFault(self):
84 self.send(b"cf")
85 return self.get_statusget_status()
86
87 @microscope.abc.SerialDeviceMixin.lock_comms
88 def get_status(self):
89 result = []
90 for cmd, stat in [
91 (b"l?", "Emission on?"),
92 (b"p?", "Target power:"),
93 (b"pa?", "Measured power:"),
94 (b"f?", "Fault?"),
95 (b"hrs?", "Head operating hours:"),
96 ]:
97 response = self.send(cmd)
98 result.append(stat + " " + response.decode())
99 return result
100
101 @microscope.abc.SerialDeviceMixin.lock_comms
102 def _do_shutdown(self) -> None:
103 # Disable laser.
104 self.disabledisable()
105 self.send(b"@cob0")
106 self.connectionconnection.flushInput()
107
108 # Initialization to do when cockpit connects.
109 @microscope.abc.SerialDeviceMixin.lock_comms
110 def initialize(self):
111 self.connectionconnection.flushInput()
112 # We don't want 'direct control' mode.
113 self.send(b"@cobasdr 0")
114 # Force laser into autostart mode.
115 self.send(b"@cob1")
116
117 # Turn the laser ON. Return True if we succeeded, False otherwise.
118 @microscope.abc.SerialDeviceMixin.lock_comms
119 def _do_enable(self):
120 _logger.info("Turning laser ON.")
121 # Turn on emission.
122 response = self.send(b"l1")
123 _logger.info("l1: [%s]", response.decode())
124
125 if not self.get_is_onget_is_on():
126 # Something went wrong.
127 _logger.error("Failed to turn on. Current status:\r\n")
128 _logger.error(self.get_statusget_status())
129 return False
130 return True
131
132 # Turn the laser OFF.
133 @microscope.abc.SerialDeviceMixin.lock_comms
134 def disable(self):
135 _logger.info("Turning laser OFF.")
136 return self.send(b"l0").decode()
137
138 # Return True if the laser is currently able to produce light.
139 @microscope.abc.SerialDeviceMixin.lock_comms
140 def get_is_on(self):
141 response = self.send(b"l?")
142 return response == b"1"
143
144 @microscope.abc.SerialDeviceMixin.lock_comms
145 def _get_power_mw(self) -> float:
146 if not self.get_is_onget_is_on():
147 return 0.0
148 success = False
149 # Sometimes the controller returns b'1' rather than the power.
150 while not success:
151 response = self.send(b"pa?")
152 if response != b"1":
153 success = True
154 return 1000 * float(response)
155
156 @microscope.abc.SerialDeviceMixin.lock_comms
157 def _set_power_mw(self, mW: float) -> None:
158 # There is no minimum power in cobolt lasers. Any
159 # non-negative number is accepted.
160 W_str = "%.4f" % (mW / 1000.0)
161 _logger.info("Setting laser power to %s W.", W_str)
162 return self.send(b"@cobasp " + W_str.encode())
163
164 def _do_set_power(self, power: float) -> None:
165 self._set_power_mw(power * self._max_power_mw)
166
167 def _do_get_power(self) -> float:
168 return self._get_power_mw() / self._max_power_mw
None initialize(self)
Definition: abc.py:339
None disable(self)
Definition: abc.py:307
bool get_is_on(self)
Definition: abc.py:1212
typing.List[str] get_status(self)
Definition: abc.py:1206
int _write(self, bytes command)
Definition: abc.py:1020
None _set_power_mw(self, float mW)
Definition: cobolt.py:157