Source code for psychopy_gammasci.gammasci

# -*- coding: utf-8 -*-
"""Gamma-Scientific light-measuring devices

Tested with S470, but should work with S480 and S490, too. 

2022 by David-Elias Künstle <david-elias.kuenstle AT uni-tuebingen.de>
----------
Implementation is based on device drivers from psychopy and ishow libraries:
    psychopy.hardware.minolta.LS110.
    ishow/calibration/devices/photometer.m.
"""
import sys

try:
    import serial
except ImportError:
    serial = False


[docs] class S470(object): """Gamma Scientific flexOptometer S470, S480, S490 You need to connect a S470 to the serial (RS232) port. This class expects a baudrate of 38400, which can be set in the device's menu. usage:: phot = S470(port) lum = phot.getLum() :parameters: port: string the serial port to connect with the photometer. Typically COM1 on Windows and /dev/ttyUSB0 or /dev/ttyS470 on Linux. n_repeat: int number of repeated measures to average for getLum """ longName = "Gamma Scientific S470/S480/S490" driverFor = ['s470', 's480', 's490'] # psychopy expects lower-case def __init__(self, port: str, n_repeat: int = 10, baudrate=38400): super(S470, self).__init__() self.n_repeat = n_repeat if not serial: raise ImportError("The module serial is needed to connect to " "photometers. On most systems this can be " "installed with\n\t easy_install pyserial") if type(port) in [int, float]: # add one so that port 1=COM1 self.portString = f'COM{port:d}' self.portNumber = port else: self.portString = str(port) self.portNumber = None self.lastLum = None self.type = 'S470' self.terminator = '\r\n' # try to open the port _linux = sys.platform.startswith('linux') if sys.platform in ('darwin', 'win32') or _linux: try: self.com = serial.Serial(self.portString, baudrate=baudrate, timeout=2) # seconds except Exception: msg = f"Couldn't connect to port {self.portString}. Is it being used by another program?" raise IOError(msg) else: msg = f"I don't know how to handle serial ports on {sys.platform}" raise IOError(msg) self.OK = True # required by psychopy
[docs] def read_line(self) -> str: """ Read a line from the serial port.""" line = self.com.read_until(expected=self.terminator.encode()).decode() if line.endswith(self.terminator): return line[:-len(self.terminator)] else: raise IOError("Expect read_line receiving message ending with " f"{self.terminator.encode('string_escape')}, got {line}")
[docs] def measure(self, n_measures: int = 1) -> list: """ Measure luminances from the serial port.""" n_measures = int(n_measures) if n_measures > 1: self.com.write(f'REA {n_measures:d}{self.terminator}'.encode()) elif n_measures == 1: self.com.write(f'REA{self.terminator}'.encode()) else: # negative numbers would result in infinite measures. raise ValueError(f"Expect n_measures as positive integer, got {n_measures}.") first_line = self.read_line() assert first_line == "", f"Expect empty line message, got '{first_line.encode()}'." lums = [] for i in range(n_measures): msg = self.read_line() lums.append(float(msg)) return lums
[docs] def getLum(self) -> float: """ Return the average luminance of repeated measures. The number of repetitions is controlled by .n_repeat. The returned luminance is set to .lastLum. This method is required by psychopy. """ lums = self.measure(self.n_repeat) self.lastLum = sum(lums) / len(lums) return self.lastLum
def __del__(self): self.com.close()

Back to top