Skip to content
Open
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
5 changes: 5 additions & 0 deletions acq4/drivers/ThorlabsDC4100/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-

__author__ = """arielle leon"""
__email__ = 'ariellel@alleninstitute.org'
__version__ = '0.1.0'
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

init needs to import the Thorlabs DC4100 class.
Also: I recommend omitting the author/email/version.

88 changes: 88 additions & 0 deletions acq4/drivers/ThorlabsDC4100/thorlabs_dc4100_led.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import serial as s
from serial import SerialException
import logging
import os


COMMANDS = {
"set_brightness": "BP {} {}",
"get_brightness": "BP? {}",
"led_on": "O {} 1",
"led_off": "O {} 0",
"return_on_off": "O? {}",
"lock_led": "A {} {}",
"register_status": "R?",
"serial_number": "S?",
"firmware": "V?",
"manufacturer": "H?",
"error_status": "E?"
}
class ThorlabsDC4100:
def __init__(self,port,baudrate,timeout):
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style comments:

  • PEP8 likes spaces after commas (and I think it makes the code easier to read).
  • Acq4 uses camelCase instead of snake_case; consistency is preferred here. (this decision was originally inherited from Qt, although I regret it somewhat at this point..)

self.port = port
self.baudrate = baudrate
self.timeout = timeout
self.dev = None
self.escape = '\n\n'
self.read_buffer = []

def led_on(self, channel: int):
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will cause a syntax error in python 2. I hope python 3 support is coming soon, but currently micromanager is also py2 only and we don't know when that will be fixed..

self._write_to_LED(COMMANDS["led_on"].format(channel))

def led_off(self,channel: int):
self._write_to_LED(COMMANDS["led_off"].format(channel))
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another minor suggestion: by rewriting _write_to_LED a little, you could turn this into

self._write_to_LED('led_off', channel)

..which reduces the amount of repeated code and makes everything more readable.


def set_brightness(self,channel:int, brightness: float):
self._write_to_LED(COMMANDS["set_brightness"].format(channel,brightness))

def get_brightness(self,channel: int):
self._write_to_LED(COMMANDS["get_brightness"].format(channel))
return self._read_from_LED()

def check_if_on(self, channel: int):
self._write_to_LED(COMMANDS["return_on_off"].format(channel))
return self._read_from_LED()

@property
def serial_number(self):
self._write_to_LED(COMMANDS["serial_number"])
return self._read_from_LED()

@property
def firmware(self):
self._write_to_LED(COMMANDS["firmware"])
return self._read_from_LED()

@property
def manufacturer(self):
self._write_to_LED(COMMANDS["manufacturer"])
return self._read_from_LED()

def connect_device(self):
try:
self.dev = s.Serial(port=self.port,baudrate=self.baudrate,timeout=self.timeout)
except SerialException:
logging.error("Device connection could not be established")

def _write_to_LED(self, command: str):
self.dev.write(f"{command} {self.escape}".encode())

def _read_from_LED(self):
while self.dev.is_open:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If self.dev.is_open becomes False before this method has returned, then it will just return None, whereas I assume raising an exception would be more appropriate. You'd also potentially have junk left in self.read_buffer. For context: serial errors are relatively common in our setup, so making this bit robust is key. I recommend reading over (and maybe using) the code in https://github.com/acq4/acq4/blob/develop/acq4/drivers/SerialDevice.py, since it incorporates many of the lessons we learned through years of dealing with serial failures.

output = self.dev.read().decode()
if len(self.read_buffer) == 0 and output == '\r':
self.dev.flush()
continue
if output == "\n":
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if I am not mistaken, it's possible for output to contain multiple bytes ending with \n, in which case we are stuck in an infinite loop here (and in general, there seem to be a few other ways we could end up stuck here forever, depending on how (un)reliable the serial communication is). Something like readUntil (https://github.com/acq4/acq4/blob/develop/acq4/drivers/SerialDevice.py#L156) might work here?

ret_value = "".join(self.read_buffer)
self.dev.flush()
self.read_buffer = []
return ret_value
else:
self.read_buffer.append(output)

def main():
led = ThorlabsDC4100(port='com12',baudrate=115200,timeout=0.5)

if __name__ == "__main__":
main()