mmcb-rs232-avt 1.0.20__py3-none-any.whl → 1.1.38__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -47,6 +47,25 @@ data structures:
47
47
  DEVICE_CACHE
48
48
  Packet
49
49
  UNIT
50
+
51
+ General note on RS232 port locking:
52
+
53
+ To make the existing code work with the expanded test setup, two types of
54
+ per-port locks are employed here.
55
+
56
+ (1) A piece of equipment connected to a single serial port may have more
57
+ than one channel, and the data structures in this library represent
58
+ equipment in terms of their individual channels. Exclusive multiprocessing
59
+ locks are used to prevent concurrent access to the same RS232 port by
60
+ different threads within a given script. This protection principally
61
+ applies to iv.py when using a multi-channel power supply such as the
62
+ Keithley 2614b.
63
+
64
+ (2) In practical scenarios, it is possible for multiple monitoring scripts
65
+ to be running on a machine that may require access to the same RS232 ports,
66
+ e.g. a PID loop is running, and a user wishes to check PSU status with
67
+ psustat.py. This is managed with a coarse exclusive file-lock based on
68
+ fcntl system calls.
50
69
  """
51
70
 
52
71
  import argparse
@@ -75,7 +94,7 @@ import matplotlib.pyplot as plt
75
94
  import numpy as np
76
95
  import serial
77
96
 
78
- from mmcb_rs232 import lexicon
97
+ from mmcbrs232 import lexicon
79
98
 
80
99
 
81
100
  ##############################################################################
@@ -83,6 +102,7 @@ from mmcb_rs232 import lexicon
83
102
  ##############################################################################
84
103
 
85
104
 
105
+ RS232_LOCK_GLOBAL = os.path.expanduser('~/.mmcb_rs232_lock_global')
86
106
  DEVICE_CACHE = os.path.expanduser('~/.cache.json')
87
107
 
88
108
 
@@ -1330,7 +1350,7 @@ def check_file_exists(filename):
1330
1350
  returns : string
1331
1351
  --------------------------------------------------------------------------
1332
1352
  """
1333
- if not os.path.exists(filename):
1353
+ if not os.path.isfile(filename):
1334
1354
  raise argparse.ArgumentTypeError(f'{filename}: file does not exist')
1335
1355
 
1336
1356
  return filename
@@ -1610,21 +1630,17 @@ def rs232_port_is_valid(com):
1610
1630
  if com.hwid == 'USB VID:PID=0403:6010 SER=210274552605B':
1611
1631
  return False
1612
1632
 
1613
- success = False
1614
- test_strings = ('FTDI', 'FT232R', 'FT232R')
1615
- test_variables = (com.manufacturer, com.product, com.description)
1616
-
1617
- for tstr, tvar in zip(test_strings, test_variables):
1618
- try:
1619
- test = tstr in tvar
1620
- except TypeError:
1621
- pass
1622
- else:
1623
- success = success or test
1624
- if test:
1625
- break
1633
+ # Define the attributes to check and the keywords to look for.
1634
+ checks = [
1635
+ (com.manufacturer, 'FTDI'),
1636
+ (com.product, 'FT232R'),
1637
+ (com.description, 'FT232R'),
1638
+ ]
1626
1639
 
1627
- return success
1640
+ return any(
1641
+ attribute and keyword in attribute
1642
+ for attribute, keyword in checks
1643
+ )
1628
1644
 
1629
1645
 
1630
1646
  def atomic_send_command_read_response(pipeline, ser, dev, command):
@@ -1899,7 +1915,7 @@ def _channel_mismatch(cache, user):
1899
1915
  return cache != user
1900
1916
 
1901
1917
 
1902
- def initial_power_supply_check(settings, pipeline, psus, channels, psuset=False):
1918
+ def initial_power_supply_check(settings, pipeline, psus, channels, psuset=False, clear=True):
1903
1919
  """
1904
1920
  Establishes RS232 communications with power supplies (as required).
1905
1921
  Checks status of channel outputs and interlocks (inhibits).
@@ -1919,6 +1935,7 @@ def initial_power_supply_check(settings, pipeline, psus, channels, psuset=False)
1919
1935
  power supply channel
1920
1936
  psuset : bool
1921
1937
  selects the error message depending on the caller
1938
+ clear : bool
1922
1939
  --------------------------------------------------------------------------
1923
1940
  returns
1924
1941
  channels : list
@@ -1979,25 +1996,26 @@ def initial_power_supply_check(settings, pipeline, psus, channels, psuset=False)
1979
1996
 
1980
1997
  port_used[dev.port] += 1
1981
1998
 
1982
- if any(outstat):
1983
- message = 'all power supply outputs must be on to proceed'
1984
- log_with_colour(logging.ERROR, message)
1985
- channels.clear()
1986
-
1987
- if any(intstat):
1988
- message = 'all power supply interlocks must be inactive to proceed'
1989
- log_with_colour(logging.ERROR, message)
1990
- channels.clear()
1991
-
1992
- if any(polstat):
1993
- if psuset:
1994
- message = 'set voltage should agree with polarity switch to proceed'
1999
+ if clear:
2000
+ if any(outstat):
2001
+ message = 'all power supply outputs must be on to proceed'
1995
2002
  log_with_colour(logging.ERROR, message)
1996
- else:
1997
- message = 'all polarity switches must agree with --forwardbias to proceed'
2003
+ channels.clear()
2004
+
2005
+ if any(intstat):
2006
+ message = 'all power supply interlocks must be inactive to proceed'
1998
2007
  log_with_colour(logging.ERROR, message)
2008
+ channels.clear()
2009
+
2010
+ if any(polstat):
2011
+ if psuset:
2012
+ message = 'set voltage should agree with polarity switch to proceed'
2013
+ log_with_colour(logging.ERROR, message)
2014
+ else:
2015
+ message = 'all polarity switches must agree with --forwardbias to proceed'
2016
+ log_with_colour(logging.ERROR, message)
1999
2017
 
2000
- channels.clear()
2018
+ channels.clear()
2001
2019
  else:
2002
2020
  message = '--debug: any connected power supplies will be ignored'
2003
2021
  log_with_colour(logging.WARNING, message)
@@ -2111,7 +2129,7 @@ def _report_interlock_status(ser, pipeline, dev):
2111
2129
  returns : none
2112
2130
  --------------------------------------------------------------------------
2113
2131
  """
2114
- assert dev.manufacturer not in {'agilent', 'hameg'},\
2132
+ assert dev.manufacturer not in {'agilent', 'hameg'}, \
2115
2133
  'function not callable for Agilent or Hameg PSU'
2116
2134
 
2117
2135
  fail = False
@@ -2477,7 +2495,11 @@ def unique(settings, psus, channels):
2477
2495
  for channel in copy.deepcopy(channels):
2478
2496
  cache = (channel.manufacturer, channel.model, channel.serial_number,
2479
2497
  channel.port, channel.channel)
2480
- if any(t(c, u) for c, u, t in zip(cache, user, test) if u is not None):
2498
+ if any(
2499
+ t(c, u)
2500
+ for c, u, t in zip(cache, user, test)
2501
+ if u is not None
2502
+ ):
2481
2503
  channels.remove(channel)
2482
2504
 
2483
2505
  single = len(channels) == 1