31_logger = logging.getLogger(__name__)
34def _get_table_value(table: bytes, key: bytes) -> bytes:
35 """Get the value for a key in a table/multiline output.
37 Some commands return something like a table of key/values. There
38 may be even empty lines on this table. This searches
for the
39 first line
with a specific key (hopefully there
's only one line
40 with such key)
and returns the associated value.
43 match = re.search(b
"(?:^|\r\n) *" + key + b
": (.*)\r\n", table)
46 "failed to find key %s on table: %s" % (key, table)
52 """Connection to a specific Toptica iBeam smart laser.
54 This class wraps the
serial connection to the device, and provides
55 access to some of its commands performing most of the parsing
and
59 port: port name (Windows)
or path to port (everything
else) to
60 connect to. For example, `/dev/ttyS1`, `COM1`,
or
65 def __init__(self, port: str):
71 serial_conn = serial.Serial(
75 bytesize=serial.EIGHTBITS,
76 stopbits=serial.STOPBITS_ONE,
77 parity=serial.PARITY_NONE,
89 self.
_serial.write(b
"echo off\r\n")
90 self.
_serial.write(b
"prompt off\r\n")
95 self.
_serial.write(b
"talk usual\r\n")
104 "Failed to confirm Toptica iBeam on %s" % (port)
107 answer = self.
command(b
"show serial")
108 if not answer.startswith(b
"SN: "):
110 "Failed to parse serial from %s" % answer
112 _logger.info(
"got connection to Toptica iBeam %s", answer.decode())
115 """Run command and return answer after minimal validation.
117 The output of a command has the format::
119 \r\nANSWER\r\n[OK]\r\n
121 The returned bytes only include `ANSWER` without its own final
122 `\r\n`. This means that the return value might be an empty
128 self.
_serial.write(command + b
"\r\n")
131 answer = self.
_serial.read_until(b
"\r\n[OK]\r\n")
133 if not answer.startswith(b
"\r\n"):
135 "answer to command %s does not start with CRLF."
136 " This may be leftovers from a previous command:"
137 " %s" % (command, answer)
139 if not answer.endswith(b
"\r\n[OK]\r\n"):
141 "Command %s failed or failed to read answer: %s"
151 if answer[2:7] == b
"%SYS-" and answer[7] != ord(b
"I"):
155 "Command %s failed: %s" % (command, answer)
163 """Activate LD driver."""
167 """Deactivate LD driver."""
171 """Set power in mW for channel 2 (normal operating level channel).
173 We don't have channel number as an argument because we only
174 want to be setting the power via channel 2 (channel 1 is the
175 bias
and we haven
't seen a laser with a channel 3 yet).
177 self.command(b"channel 2 power %f" % power)
180 """Returns actual laser power in µW."""
181 answer = self.
command(b
"show power")
182 if not answer.startswith(b
"PIC = ")
and not answer.endswith(b
" uW "):
184 "failed to parse power from answer: %s" % answer
186 return float(answer[7:-5])
189 """Returns actual status of the LD driver (ON or OFF)."""
190 return self.
command(b
"status laser")
192 def show_max_power(self) -> float:
196 table = self.
command(b
"show satellite")
197 value = _get_table_value(table, key=b
"Pmax")
198 if not value.endswith(b
" mW"):
200 "failed to parse power from %s" % value
202 return float(value[:-3])
209 """Toptica iBeam smart laser.
211 Control of laser power is performed by setting the power level on
213 unmodified
and so defines the lowest level power.
216 def __init__(self, port: str, **kwargs) ->
None:
217 super().__init__(**kwargs)
232 def _do_shutdown(self) -> None:
236 status: typing.List[str] = []
240 self.
_conn.laser_on()
243 self.
_conn.laser_off()
246 state = self.
_conn.status_laser()
249 elif state == b
"OFF":
253 "Unexpected laser status: %s" % state.decode()
256 def _get_max_power_mw(self) -> float:
259 def _get_power_mw(self) -> float:
260 return self.
_conn.show_power_uW() * (10**-3)
262 def _set_power_mw(self, mw: float) ->
None:
263 self.
_conn.set_normal_channel_power(mw)
265 def _do_set_power(self, power: float) ->
None:
268 def _do_get_power(self) -> float:
float show_power_uW(self)
None set_normal_channel_power(self, float power)
bytes command(self, bytes command)
float _get_max_power_mw(self)
typing.List[str] get_status(self)
None _set_power_mw(self, float mw)
float _get_power_mw(self)