Skip to content

Commit

Permalink
Updated to version to 1.1.5. Changed how the pytoml information is fo…
Browse files Browse the repository at this point in the history
…und. Updated dependencies.
  • Loading branch information
agentsmith29 committed Aug 8, 2024
1 parent 17d3162 commit 6d538f3
Show file tree
Hide file tree
Showing 13 changed files with 177 additions and 42 deletions.
19 changes: 18 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,24 @@ python -m venv .venv
pip install -r requirements.txt
```

# Usage
After installing, you need to set the pathes to the Sacher Libaray using
the `config.py` file.

```python
conf = Laser.Config()
conf.save()
#conf.load('./LaserConfig.yaml', as_auto_save=True)
conf.autosave(True, './LaserConfig.yaml')

# Set the path to the EposCmd64.dll and the SacherMotorControl.pyd
conf.epos_dll.set(pathlib.Path(
f'{Laser.__rootdir__}/libs/SacherLib/PythonMotorControlClass/EposCmd64.dll'))

conf.motor_control_pyd.set(pathlib.Path(
f'{Laser.__rootdir__}/libs/SacherLib/PythonMotorControlClass/'
f'lib/Python312/SacherMotorControl.pyd'))
```
See (main.py)[./examples/main.py] for an example.

Run the main script:

Expand Down
2 changes: 1 addition & 1 deletion examples/CaptDeviceConfig.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# - Configuration file stored 2024-08-07 15:54:06.643611 -
# - Configuration file stored 2024-08-08 13:18:18.949366 -
CaptDeviceConfig: #!!python/object:controller.CaptDeviceConfig
selected_device_index: 0 # Selected device: Selected device from the device list provided by the DreamWaves API.
sample_rate: 500 # Sample rate: Sample rate of the device
Expand Down
10 changes: 6 additions & 4 deletions examples/LaserConfig.yaml
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
# - Configuration file stored 2024-07-31 11:25:23.500548 -
# - Configuration file stored 2024-08-08 13:17:14.134241 -
LaserConfig: #!!python/object:controller.LaserConfig
epos_dll: "@Path:<C:/Users/myjustice/Documents/workspace/fs.lasercontrol/src/SacherECLControl/libs/SacherLib/PythonMotorControlClass/EposCmd64.dll>" # epos_dll: None
motor_control_pyd: "@Path:<C:/Users/myjustice/Documents/workspace/fs.lasercontrol/src/SacherECLControl/libs/SacherLib/PythonMotorControlClass/lib/Python312/SacherMotorControl.pyd>" # motor_control_pyd: None
wl_sweep_start: 857 # wl_sweep_start: None
wl_sweep_stop: 870 # wl_sweep_stop: None
velocity: 10.0 # velocity: None
acceleration: 2.0 # acceleration: None
deceleration: 2.0 # deceleration: None
velocity: 2.0 # velocity: None
acceleration: 1.0 # acceleration: None
deceleration: 1.0 # deceleration: None
available_ports: ['USB0', 'USB1', 'USB2', 'USB3', 'USB4', 'USB5', 'USB6', 'USB7', 'USB8', 'USB9'] # available_ports: None
port: "USB0" # port: None
10 changes: 10 additions & 0 deletions examples/Main_ADScope.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import logging
import sys
import os
import pathlib
from multiprocessing import Value

from rich.logging import RichHandler
Expand Down Expand Up @@ -32,6 +33,7 @@
#conf_capt_dev.load("CaptDeviceConfig.yaml")
conf_capt_dev.autosave()


start_capture_flag = Value('i', 0)

capt_dev_model = captdev.Model(conf_capt_dev)
Expand All @@ -40,6 +42,14 @@


conf = Laser.Config()
# Set the path to the EposCmd64.dll and the SacherMotorControl.pyd
conf.epos_dll.set(pathlib.Path(
f'{Laser.__rootdir__}/libs/SacherLib/PythonMotorControlClass/EposCmd64.dll'))

conf.motor_control_pyd.set(pathlib.Path(
f'{Laser.__rootdir__}/libs/SacherLib/PythonMotorControlClass/'
f'lib/Python312/SacherMotorControl.pyd'))

model = Laser.Model(conf)
controller = Laser.Controller(model, start_capture_flag)
window = Laser.View(model, controller)
Expand Down
21 changes: 15 additions & 6 deletions examples/main.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import logging
import os
import pathlib
import sys
from PySide6.QtWidgets import QApplication
from rich.logging import RichHandler
Expand All @@ -18,15 +20,24 @@
else:
app = QApplication.instance()



conf = Laser.Config()
conf.save()
#conf.load('./LaserConfig.yaml', as_auto_save=True)
conf.autosave(True, './LaserConfig.yaml')

# Set the path to the EposCmd64.dll and the SacherMotorControl.pyd
conf.epos_dll.set(pathlib.Path(
f'{Laser.__rootdir__}/libs/SacherLib/PythonMotorControlClass/EposCmd64.dll'))

conf.motor_control_pyd.set(pathlib.Path(
f'{Laser.__rootdir__}/libs/SacherLib/PythonMotorControlClass/'
f'lib/Python312/SacherMotorControl.pyd'))



conf.module_log_level = logging.DEBUG
conf.module_log_enabled = True


model = Laser.Model(conf)
controller = Laser.Controller(model, None)
controller.internal_log_level = logging.DEBUG
Expand All @@ -38,8 +49,6 @@
# model.sweep_stop_wavelength,
#)


window.show()


sys.exit(app.exec())
sys.exit(app.exec())
6 changes: 3 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ packages = ["src/SacherECLControl"]

[project]
name = "PySacherECLControl"
version = "1.1.3"
version = "1.1.5"
authors = [
{ name="Christoph Schmidt", email="[email protected]" },
]
Expand All @@ -22,10 +22,10 @@ dependencies = [
'PySide6',
'rich',
'pyyaml',
'PyADScopeControl>=1.1.4',
'PyADScopeControl>=1.1.7',
'PySide6WidgetCollection>=1.0.2', # important, otherwise AboutDialog is not available
'mpPy6',
'confPy6'
'confPy6>=1.3.1'
]
classifiers = [
"Programming Language :: Python :: 3",
Expand Down
4 changes: 2 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ pyyaml

# my packages
mpPy6
confPy6
PyADScopeControl>=1.1.4
confPy6>=1.3.1
PyADScopeControl>=1.1.7
PySide6WidgetCollection>=1.0.2, # important, otherwise AboutDialog is not available


Expand Down
58 changes: 58 additions & 0 deletions src/SacherECLControl/Helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# ======================================================================================================================
# EposCMD64.dll is needed, thus, try to copy it
# ======================================================================================================================
import os
import pathlib
import shutil



def copyEposDLL(epos_dll="./EposCMD64.dll", logger=None):
if logger is None:
logger = print
else:
logger = logger.info

dll_dir = pathlib.Path(epos_dll)
dll_name = os.path.basename(epos_dll)
#epos_dll_name = pathlib.Path(epos_dll_name)
logger(f"Copying {dll_dir} to {os.getcwd()}")

if not dll_dir.exists():
raise FileNotFoundError(f"Could not find {epos_dll}")

dll_dir = str(dll_dir.resolve())
dll_dest = f"{os.getcwd()}/{dll_name}" # Copy the file to the workspace folder
# Copy the file "EposCMD64.dll" to the current dir
if not pathlib.Path(dll_dest).exists():
shutil.copyfile(dll_dir, f"{os.getcwd()}/EposCMD64.dll")
logger(f"Copied {dll_name} to {os.getcwd()}")
elif pathlib.Path(dll_dest).exists():
logger(f"{dll_name} already exists in {os.getcwd()}")


# Check if the file was copied
if not pathlib.Path(dll_dest).exists():
raise FileNotFoundError(f"Could not copy {dll_name} to {os.getcwd()}")

def check_if_git_or_pip():
# check if a folder .git is present ../../
git_dir = pathlib.Path(__file__).parent.parent.parent / ".git"
if git_dir.exists():
print("git_dir:", git_dir)
else:
print("git_dir does not exist")

def get_pyprojecttoml() -> pathlib.Path:
# is found in ../../pyconfig.toml
pytoml_via_git = pathlib.Path(__file__).parent.parent.parent / "pyproject.toml"
# found in ./pyconfig.toml: Copied to the root dir
pytoml_via_pip = pathlib.Path(__file__).parent / "pyproject.toml"

if pytoml_via_git.exists():
#print("pytoml_via_git:", pytoml_via_git)
return pytoml_via_git.resolve().absolute()
elif pytoml_via_pip.exists():
#print("pytoml_via_pip:", pytoml_via_pip)
return pytoml_via_pip.resolve().absolute()

10 changes: 10 additions & 0 deletions src/SacherECLControl/LaserConfig.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import logging
import os
from pathlib import Path

import confPy6 as cfg

Expand All @@ -7,6 +9,14 @@ class LaserConfig(cfg.ConfigNode):

def __init__(self) -> None:
super().__init__()

# Set the path to the EposCmd64.dll
self.epos_dll = cfg.Field(Path("./EposCmd64.dll"))
# Set the path to the SacherMotorControl.pyd
self.motor_control_pyd = cfg.Field(
Path(f"./SacherMotorControl.pyd"),
env_var="MOTOR_CONTROL_PYD")

self.wl_sweep_start = cfg.Field(857)
self.wl_sweep_stop = cfg.Field(870)
self.velocity = cfg.Field(2.0)
Expand Down
39 changes: 21 additions & 18 deletions src/SacherECLControl/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,32 @@
import shutil
import sys

from WidgetCollection.Tools.PyProjectExtractor import extract_pyproject_info

from . import Helpers

sys.path.append(os.path.join(os.path.dirname(__file__), '../'))

# from SacherECLControl.controller.LaserCon import LaserCon
dll_dir = pathlib.Path(
f"{os.path.dirname(os.path.realpath(__file__))}/libs/SacherLib/PythonMotorControlClass/EposCMD64.dll")
dll_dir = str(dll_dir.resolve())
dll_dest = f"{os.getcwd()}/EposCMD64.dll"
# Copy the file "EposCMD64.dll" to the current dir
if not pathlib.Path(dll_dest).exists():
shutil.copyfile(dll_dir, f"{os.getcwd()}/EposCMD64.dll")

from WidgetCollection.Tools.PyProjectExtractor import extract_pyproject_info

pytoml = pathlib.Path(__file__).parent.parent.parent
if not (pytoml / "pyproject.toml").exists():
# if installed via pip
pytoml = pathlib.Path(__file__)
# ======================================================================================================================
# The pyconfig.toml file is needed, to get the metadata. Depending on the installation method (pip or git) the file
# is found in different places.
# ======================================================================================================================
pytoml = Helpers.get_pyprojecttoml()
def try_and_set(func, *args, **kwargs):
try:
return func(*args, **kwargs)
except Exception as e:
print(f"Error reading '{args[1]}' from {pathlib.Path(args[0])}: {e}")
return "unknown"

__version__ = extract_pyproject_info(pytoml, "version")
__author__ = extract_pyproject_info(pytoml, "author")
__description__ = extract_pyproject_info(pytoml, "description")
__license__ = extract_pyproject_info(pytoml, "license")
__url__ = extract_pyproject_info(pytoml, "url")
__rootdir__ = os.path.dirname(os.path.realpath(__file__))
__version__ = try_and_set(extract_pyproject_info, pytoml.parent, "version")
__author__ = try_and_set(extract_pyproject_info, pytoml.parent, "author")
__description__ = try_and_set(extract_pyproject_info, pytoml.parent, "description")
__license__ = try_and_set(extract_pyproject_info, pytoml.parent, "license")
__url__ = try_and_set(extract_pyproject_info, pytoml.parent, "url")

# For correctly display the icon in the taskbar
myappid = f'agentsmith29.SacherECLControl.{__version__}' # arbitrary string
Expand Down
10 changes: 8 additions & 2 deletions src/SacherECLControl/controller/LaserDeviceControl.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from PySide6.QtCore import Signal
from mpPy6.CProcessControl import CProcessControl

from SacherECLControl.controller.multiprocess.MPLaserDevice import MPLaserDevice
from SacherECLControl import Helpers
from SacherECLControl.model.LaserControlModel import LaserControlModel


Expand Down Expand Up @@ -46,6 +46,11 @@ def __init__(self, model: LaserControlModel,
start_capture_flag: Value, module_log=True, module_log_level=logging.WARNING):
super().__init__(module_log=module_log, module_log_level=module_log_level)

# This is a workaround, otherwise the dll and pyd object import would not work
# Reason: We need assign the correct path beforehand. If we would first try to import the MPLaserDevice class
# the pathes would net be set.
# TODO: Find a better approach than this hacky way?
from SacherECLControl.controller.multiprocess.MPLaserDevice import MPLaserDevice
self.model = model

self.lock = Lock()
Expand All @@ -57,7 +62,8 @@ def __init__(self, model: LaserControlModel,
self.register_child_process(MPLaserDevice,
self._laser_moving_flag,
self._laser_finished_flag,
start_capture_flag)
start_capture_flag,
self.model.laser_config.epos_dll.get())

self.connected_changed.connect(self._on_connected_changed)

Expand Down
25 changes: 21 additions & 4 deletions src/SacherECLControl/controller/multiprocess/MPLaserDevice.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
import os
import pathlib
import sys
import time
from multiprocessing import Value

import mpPy6
from mpPy6.CProperty import CProperty

from SacherECLControl import Helpers, __rootdir__

# Copy the dll to the startup directory

try:
spath = str(pathlib.Path(os.getenv("MOTOR_CONTROL_PYD")).absolute().parent.as_posix())
sys.path.append(spath)
import SacherMotorControl as LaserLib

except Exception as e:
print(f"Warning: Could not import SacherMotorControl: {e}. Using LaserLibSimulator instead.")
from SacherECLControl.libs import LaserLibSimulator as LaserLib

from SacherECLControl.libs.SacherLib.PythonMotorControlClass.lib.Python312 import SacherMotorControl as LaserLib

#from SacherECLControl.libs import LaserLibSimulator as LaserLib

Expand All @@ -21,12 +30,22 @@ def __init__(self, state_queue, cmd_queue,
laser_moving_flag: Value,
laser_finished_flag: Value,
start_capture_flag: Value,
dll_copy_path,
kill_flag: Value,
internal_log, internal_log_level, log_file):
super().__init__(state_queue, cmd_queue,
kill_flag=kill_flag,
internal_log=internal_log, internal_log_level=internal_log_level, log_file=log_file)


self.dll_copy_path = dll_copy_path
#import importlib.util
#import sys
#spec = importlib.util.spec_from_file_location(module_name, module_name_path)
#foo = importlib.util.module_from_spec(spec)
#sys.modules[module_name] = foo
#spec.loader.exec_module(foo)

# if not self.logger.handlers:
# self.logger.setLevel(level=logging.DEBUG)
# self.logger.disabled = False
Expand All @@ -50,6 +69,7 @@ def __init__(self, state_queue, cmd_queue,
self._wavelength_sweep_running = False

def postrun_init(self):
Helpers.copyEposDLL(f"{self.dll_copy_path}", logger=self.logger)
self.laser = LaserLib.Motor()

# ==================================================================================================================
Expand Down Expand Up @@ -317,9 +337,6 @@ def get_laser_settings(self, *args, **kwargs):
self.get_acceleration()
self.get_deceleration()




@CProperty
def laser_is_moving(self):
return self._laser_moving
Expand Down
Loading

0 comments on commit 6d538f3

Please sign in to comment.