mmcb-rs232-avt 1.0.13__py3-none-any.whl → 1.0.18__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.
mmcb_rs232/dmm.py ADDED
@@ -0,0 +1,126 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Read values from the Keithley DMM6500.
4
+ """
5
+
6
+ import argparse
7
+ import itertools
8
+ import sys
9
+ import time
10
+
11
+ from mmcb import common
12
+ from mmcb import dmm_interface
13
+
14
+
15
+ ##############################################################################
16
+ # command line option handler
17
+ ##############################################################################
18
+
19
+
20
+ def check_arguments():
21
+ """
22
+ handle command line options
23
+
24
+ --------------------------------------------------------------------------
25
+ args : none
26
+ --------------------------------------------------------------------------
27
+ returns
28
+ args : <class 'argparse.Namespace'>
29
+ --------------------------------------------------------------------------
30
+ """
31
+ parser = argparse.ArgumentParser(
32
+ description='Reads voltage or current from the Keithley DMM6500.'
33
+ )
34
+ parser.add_argument(
35
+ '-p', '--plain',
36
+ action='store_true',
37
+ help='print the requested figure only')
38
+ parser.add_argument(
39
+ '-c', '--capacitance',
40
+ action='store_true',
41
+ help='Read capacitance (F)')
42
+ parser.add_argument(
43
+ '--currentac',
44
+ action='store_true',
45
+ help='Read AC current (A)')
46
+ parser.add_argument(
47
+ '-i', '--currentdc',
48
+ action='store_true',
49
+ help='Read DC current (A)')
50
+ parser.add_argument(
51
+ '-r', '--resistance',
52
+ action='store_true',
53
+ help='Read two-wire resistance (\u03a9)')
54
+ parser.add_argument(
55
+ '-t', '--temperature',
56
+ action='store_true',
57
+ help='Read temperature (\u00b0C)')
58
+ parser.add_argument(
59
+ '--voltageac',
60
+ action='store_true',
61
+ help='Read AC voltage (V)')
62
+ parser.add_argument(
63
+ '-v', '--voltagedc',
64
+ action='store_true',
65
+ help='Read DC voltage (V)')
66
+
67
+ args = parser.parse_args()
68
+
69
+ return args
70
+
71
+
72
+ ##############################################################################
73
+ # main
74
+ ##############################################################################
75
+
76
+
77
+ def main():
78
+ """ Read values from the Keithley DMM6500 """
79
+
80
+ args = check_arguments()
81
+
82
+ dmm = dmm_interface.Dmm6500()
83
+ if dmm.init_failed:
84
+ print('could not initialise serial port')
85
+ return 3
86
+
87
+ configure = {
88
+ 'capacitance': dmm.configure_read_capacitance,
89
+ 'currentac': dmm.configure_read_ac_current,
90
+ 'currentdc': dmm.configure_read_dc_current,
91
+ 'resistance': dmm.configure_read_resistance,
92
+ 'temperature': dmm.configure_read_temperature,
93
+ 'voltagedc': dmm.configure_read_dc_voltage,
94
+ 'voltageac': dmm.configure_read_ac_voltage,
95
+ }
96
+
97
+ # AC quantities sometimes return None on the first attempt
98
+ retries = 3
99
+
100
+ success = []
101
+ params = []
102
+ for function, required in vars(args).items():
103
+ if not required or function=='plain':
104
+ continue
105
+
106
+ configure[function]()
107
+
108
+ value = None
109
+ for _ in itertools.repeat(None, retries):
110
+ value = dmm.read_value()
111
+ if value is not None:
112
+ success.append(True)
113
+ break
114
+ time.sleep(0.1)
115
+
116
+ if args.plain:
117
+ print(value)
118
+ else:
119
+ print(f'{function}, {common.si_prefix(value)}, {value}')
120
+
121
+ return 0 if any(success) else 3
122
+
123
+
124
+ ##############################################################################
125
+ if __name__ == '__main__':
126
+ sys.exit(main())
@@ -0,0 +1,162 @@
1
+ """
2
+ Read values from the Keithley DMM6500.
3
+
4
+ https://docs.python.org/3.6/library/weakref.html#comparing-finalizers-with-del-methods
5
+ """
6
+
7
+ import threading
8
+ import weakref
9
+
10
+ import serial
11
+
12
+ from mmcb import common
13
+ from mmcb import lexicon
14
+
15
+
16
+ class Production:
17
+ """
18
+ Locks to support threaded operation in the underlying library code (1 lock
19
+ per serial port).
20
+ """
21
+
22
+ def __init__(self, instrument_channels):
23
+ """
24
+ -----------------------------------------------------------------------
25
+ args
26
+ instrument_channels : list of <class 'mmcb.common.Channel'>
27
+ -----------------------------------------------------------------------
28
+ returns : none
29
+ -----------------------------------------------------------------------
30
+ """
31
+ self.portaccess = {
32
+ port: threading.Lock()
33
+ for port in {channel.port for channel in instrument_channels}
34
+ }
35
+
36
+
37
+ class Dmm6500:
38
+ """
39
+ Connection and reading from Keithley DMM 6500.
40
+ """
41
+
42
+ _cached_instruments = common.cache_read({'instrument'})
43
+
44
+ _channels = []
45
+ for _port, _details in _cached_instruments.items():
46
+ (
47
+ _config,
48
+ _device_type,
49
+ _serial_number,
50
+ _model,
51
+ _manufacturer,
52
+ _device_channels,
53
+ _release_delay,
54
+ ) = _details
55
+
56
+ for _device_channel in _device_channels:
57
+ _channels.append(
58
+ common.Channel(
59
+ _port,
60
+ _config,
61
+ _serial_number,
62
+ _model,
63
+ _manufacturer,
64
+ _device_channel,
65
+ _device_type,
66
+ _release_delay,
67
+ None,
68
+ )
69
+ )
70
+
71
+ _pipeline = Production(_channels)
72
+
73
+ try:
74
+ _channel = _channels[0]
75
+ except IndexError:
76
+ pass
77
+
78
+ def __init__(self):
79
+ try:
80
+ self._ser = serial.Serial(port=self._channel.port)
81
+ except OSError:
82
+ self.init_failed = True
83
+ else:
84
+ self.init_failed = False
85
+ self._finalizer = weakref.finalize(self, self._ser.close)
86
+ self._ser.apply_settings(self._channel.config)
87
+ self._ser.reset_input_buffer()
88
+ self._ser.reset_output_buffer()
89
+
90
+ def remove(self):
91
+ """manual garbage collection: close serial port"""
92
+ self._finalizer()
93
+
94
+ @property
95
+ def removed(self):
96
+ """check (indirectly) if the serial port has been closed"""
97
+ return not self._finalizer.alive
98
+
99
+ def _send_command(self, command):
100
+ """
101
+ Issue command to instrument.
102
+
103
+ -----------------------------------------------------------------------
104
+ args
105
+ command : string
106
+ -----------------------------------------------------------------------
107
+ returns : none
108
+ -----------------------------------------------------------------------
109
+ """
110
+ common.send_command(
111
+ self._pipeline,
112
+ self._ser,
113
+ self._channel,
114
+ lexicon.instrument(self._channel.model, command),
115
+ )
116
+
117
+ def configure_read_capacitance(self):
118
+ self._send_command('configure to read capacitance')
119
+
120
+ def configure_read_ac_current(self):
121
+ self._send_command('configure to read ac current')
122
+
123
+ def configure_read_dc_current(self):
124
+ self._send_command('configure to read dc current')
125
+
126
+ def configure_read_resistance(self):
127
+ self._send_command('configure to read resistance')
128
+
129
+ def configure_read_temperature(self):
130
+ self._send_command('configure to read temperature')
131
+
132
+ def configure_read_dc_voltage(self):
133
+ self._send_command('configure to read dc voltage')
134
+
135
+ def configure_read_ac_voltage(self):
136
+ self._send_command('configure to read ac voltage')
137
+
138
+ def read_value(self):
139
+ """
140
+ Read the value of the previously configured parameter from the
141
+ instrument.
142
+
143
+ -----------------------------------------------------------------------
144
+ args : none
145
+ -----------------------------------------------------------------------
146
+ returns
147
+ value : float or None
148
+ -----------------------------------------------------------------------
149
+ """
150
+ response = common.atomic_send_command_read_response(
151
+ self._pipeline,
152
+ self._ser,
153
+ self._channel,
154
+ lexicon.instrument(self._channel.model, 'read value'),
155
+ )
156
+
157
+ try:
158
+ value = float(response)
159
+ except ValueError:
160
+ value = None
161
+
162
+ return value