Source code for etho.services.NICounterZeroService

from .ZeroService import BaseZeroService
import time
import sys
import numpy as np
from . import register_service
from .utils.log_exceptions import for_all_methods, log_exceptions
from ..utils.config import undefaultify
import logging
import threading

try:
    import PyDAQmx as daq

    pydaqmx_import_error = None
except (ImportError, NotImplementedError) as pydaqmx_import_error:
    pass


[docs] @for_all_methods(log_exceptions(logging.getLogger(__name__))) @register_service class NIC(BaseZeroService): """NI DAQmx Counter service for generating pulse trains via a digital output, for instance as an external frame trigger for cameras. """ LOGGING_PORT = 1450 # set this to range 1420-1460 SERVICE_PORT = 4250 # last to digits match logging output_channels - but start with "42" instead of "14" SERVICE_NAME = "NIC" # short, uppercase, 3-letter ID of the service (equals class name) CLIENT_START_GROUP = "trigger" @classmethod def setup_client(cls, service_key, service_index, prot, defaults, playlistfile, save_prefix, preview, new_console): this = defaults.copy() this.update(prot[service_key]) if prot[service_key].get("port") is None: prot[service_key]["port"] = cls.SERVICE_PORT + service_index service = cls.make( this["serializer"], this["host"], this["python_exe"], new_console=new_console, port=prot[service_key]["port"], ) params = undefaultify(prot[service_key]) service.setup( params["output_channel"], prot["maxduration"] + 10, params["frequency"], params["duty_cycle"], params, ) save_suffix = f"_{service_index + 1}" if service_index > 0 else "" service.init_local_logger(f"{this['savefolder']}/{save_prefix}/{save_prefix}{save_suffix}_nic.log") return service def setup(self, output_channel, duration, frequency, duty_cycle, params): """Setup the counter service (intiates the digital output channels). Args: output_channels (str): Digital output channel, e.g. "/dev1/port0/line0:1" duration (float): Duration of the service. frequency (float): Frequency of the pulse train in Hz. duty_cycle (float): Duty cycle (pulse duration/period = duration * frequency) of the pulse train. params (_type_): Unused. Raises: pydaqmx_import_error: Raised when the pydaqmx could not be imported. """ if pydaqmx_import_error is not None: raise pydaqmx_import_error self._time_started = None self.duration = float(duration) self.task = daq.Task() self.task.CreateCOPulseChanFreq(output_channel, "", daq.DAQmx_Val_Hz, daq.DAQmx_Val_Low, 0.0, frequency, duty_cycle) self.task.CfgImplicitTiming(daq.DAQmx_Val_ContSamps, 1000) if self.duration > 0: # if zero, will stop when nothing is to be outputted self._thread_timer = threading.Timer(self.duration, self.finish, kwargs={"stop_service": True}) def start(self): self.task.StartTask() self.log.warning("Started") self._time_started = time.time() if hasattr(self, "_thread_timer"): self.log.warning(f"duration {self.duration} seconds") self._thread_timer.start() self.log.warning("finish timer started") def stop(self): self.task.StopTask() self.log.warning("Stopped") def finish(self, stop_service=False): self.log.warning("stopping") self.stop() time.sleep(0.2) self.task.ClearTask() self.cleanup() # clean up code here self.log.warning(" stopped ") # mode log file and savefilename if stop_service: time.sleep(0.2) self.service_stop() return True def is_busy(self): return self._time_started is not None def test(self): return True def cleanup(self): # self.finish() # your code here return True
if __name__ == "__main__": if len(sys.argv) > 1: ser = sys.argv[1] else: ser = "default" if len(sys.argv) > 2: port = sys.argv[2] else: port = NIC.SERVICE_PORT s = NIC(serializer=ser) s.bind("tcp://0.0.0.0:{0}".format(port)) # broadcast on all IPs s.run()