Skip to content

Commit ea6a36f

Browse files
committed
Initial commit.
0 parents  commit ea6a36f

File tree

338 files changed

+9648
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

338 files changed

+9648
-0
lines changed

.gitignore

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# From https://github.com/github/gitignore
2+
# Byte-compiled / optimized / DLL files
3+
__pycache__/
4+
*.py[cod]
5+
*$py.class
6+
7+
# C extensions
8+
*.so
9+
10+
# Distribution / packaging
11+
.Python
12+
env/
13+
build/
14+
develop-eggs/
15+
dist/
16+
downloads/
17+
eggs/
18+
.eggs/
19+
lib/
20+
lib64/
21+
parts/
22+
sdist/
23+
var/
24+
*.egg-info/
25+
.installed.cfg
26+
*.egg
27+
28+
# PyInstaller
29+
# Usually these files are written by a python script from a template
30+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
31+
*.manifest
32+
*.spec
33+
34+
# Installer logs
35+
pip-log.txt
36+
pip-delete-this-directory.txt
37+
38+
# Unit test / coverage reports
39+
htmlcov/
40+
.tox/
41+
.coverage
42+
.coverage.*
43+
.cache
44+
nosetests.xml
45+
coverage.xml
46+
*,cover
47+
.hypothesis/
48+
49+
# Translations
50+
*.mo
51+
*.pot
52+
53+
# Django stuff:
54+
*.log
55+
local_settings.py
56+
57+
# Sphinx documentation
58+
docs/_build/
59+
60+
# PyBuilder
61+
target/
62+
63+
# Ipython Notebook
64+
.ipynb_checkpoints
65+
66+
# pyenv
67+
.python-version
68+
69+
# Ignore .alias and .lvlps files
70+
*.aliases
71+
*.lvlps

CHANGES.txt

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
v15.0.0, 2-9-2015 -- Initial release.

CREDITS

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
https://github.com/github/gitignore
2+
Copyright (c) 2016 GitHub, Inc.
3+
4+
Permission is hereby granted, free of charge, to any person obtaining a
5+
copy of this software and associated documentation files (the "Software"),
6+
to deal in the Software without restriction, including without limitation
7+
the rights to use, copy, modify, merge, publish, distribute, sublicense,
8+
and/or sell copies of the Software, and to permit persons to whom the
9+
Software is furnished to do so, subject to the following conditions:
10+
11+
The above copyright notice and this permission notice shall be included in
12+
all copies or substantial portions of the Software.
13+
14+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20+
DEALINGS IN THE SOFTWARE.

LICENSE.txt

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
The MIT License (MIT)
2+
Copyright (c) 2016 National Instruments
3+
4+
Permission is hereby granted, free of charge, to any person obtaining a copy of
5+
this software and associated documentation files (the "Software"), to deal in
6+
the Software without restriction, including without limitation the rights to
7+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
8+
of the Software, and to permit persons to whom the Software is furnished to do
9+
so, subject to the following conditions:
10+
11+
The above copyright notice and this permission notice shall be included in all
12+
copies or substantial portions of the Software.
13+
14+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20+
SOFTWARE.

MANIFEST.in

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
include *.txt
2+
recursive-include docs *
3+
recursive-include lv_listener *
4+
recursive-include labview_automation *

README.md

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
Python LabVIEW Automation (labview_automation)
2+
==============================================
3+
4+
Python LabVIEW Automation labview_automation is a Python package to make it
5+
easy to call LabVIEW VirtualInstruments (VIs) from Python. It includes a
6+
Pythonic interface to call VIs and a class to interact with LabVIEW executables
7+
on Windows.
8+
9+
To facilitate this interaction LabVIEW is started with a VI that listens for
10+
tcp messages. The Python interface sends BSON (see bsonspec.org) encoded
11+
messages to the VI which then performs the commands.
12+
13+
LabVIEW can be started on a remote machine using hoplite. Since the interface
14+
between Python and LabVIEW is tcp the messages can be sent to another machine.
15+
16+
Installation
17+
------------
18+
labview_automation can be installed by cloning the master branch and then
19+
in a command line in the directory of setup.py run:
20+
21+
pip install --pre .
22+
23+
24+
Simple Local Example
25+
--------------------
26+
You can set controls on the front panel of the VIs that you execute by adding
27+
members to a dictionary where each member represents a different control of
28+
the given name. Controls can be numerics, strings, booleans, arrays, or
29+
clusters of the same types.
30+
31+
`run_vi_synchronous` runs the VI synchronously and returns a dictionary of
32+
all the indicators on the VI.
33+
34+
from labview_automation import LabVIEW
35+
lv = LabVIEW()
36+
lv.start() # Launches the active LabVIEW with the listener VI
37+
with lv.client() as c:
38+
control_values = {
39+
"DBL Control": 5.0,
40+
"String Control": "Hello World!",
41+
"Error In": {
42+
"Status": False,
43+
"Code": 0,
44+
"Source": ""
45+
}
46+
}
47+
indicators = c.run_vi_synchronous(
48+
vi_path, control_values)
49+
print(indicators['Result'])
50+
error_message = c.get_error_description(indicators['Error Out'])
51+
lv.kill() # Stop LabVIEW
52+
53+
Development
54+
-----------
55+
All LabVIEW code is developed using LabVIEW 2014 SP1 x86.
56+
57+
Pull requests for Python code should adhere to PEP8.
58+
59+
License
60+
-------
61+
The MIT License (MIT)
62+
Copyright (c) 2016 National Instruments
63+
64+
Permission is hereby granted, free of charge, to any person obtaining a copy of
65+
this software and associated documentation files (the "Software"), to deal in
66+
the Software without restriction, including without limitation the rights to
67+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
68+
of the Software, and to permit persons to whom the Software is furnished to do
69+
so, subject to the following conditions:
70+
71+
The above copyright notice and this permission notice shall be included in all
72+
copies or substantial portions of the Software.
73+
74+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
75+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
76+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
77+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
78+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
79+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
80+
SOFTWARE.

labview_automation/__init__.py

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
__all__ = ['client', 'labview']
2+
3+
from labview_automation.client import LabVIEWClient
4+
from labview_automation.labview import LabVIEW

labview_automation/client.py

+172
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
import socket
2+
import struct
3+
import bson
4+
5+
6+
class Error(Exception):
7+
"""
8+
Class for errors which occur while calling a LabVIEW VI
9+
"""
10+
11+
def __init__(self, code, source, message):
12+
self.code = code
13+
self.source = source
14+
self.message = message
15+
16+
17+
class LabVIEWClient(object):
18+
19+
"""
20+
This class is a simple wrapper around TCP methods that communicate with the
21+
LabVIEW Listener component
22+
"""
23+
24+
def __init__(self, address, port=2552):
25+
"""
26+
:param address: Address of the remote computer running the LVListener
27+
eg. 10.2.13.32
28+
:param port: Port of the remote computer LVListener is listening on
29+
(default: 2552)
30+
"""
31+
self.address = address
32+
self.port = port
33+
34+
def __enter__(self):
35+
# Attempt to establish a TCP connection to the listener
36+
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
37+
s.connect((self.address, self.port))
38+
self.connection = s
39+
return self
40+
41+
def __exit__(self, type, value, tb):
42+
# Only close the socket if this method is called. This enables the user
43+
# to call run_vi_synchronous multiple times on this object
44+
if self.connection:
45+
self.connection.close()
46+
47+
def _check_for_error(self, return_dict):
48+
"""
49+
Checks for an error being returned in the recieved dictionary.
50+
Raises an error if the status is true.
51+
"""
52+
if 'RunVIState_Status' not in return_dict:
53+
return
54+
if return_dict['RunVIState_Status']:
55+
error = {'code': return_dict['RunVIState_Code'],
56+
'status': return_dict['RunVIState_Status'],
57+
'source': return_dict['RunVIState_Source']}
58+
raise Error(
59+
return_dict['RunVIState_Code'],
60+
return_dict['RunVIState_Source'],
61+
self.describe_error(error))
62+
63+
def run_vi_synchronous(self, vi_path, control_values, run_options=0,
64+
open_frontpanel=False, indicator_names=[]):
65+
"""
66+
:param vi_path: Absolute path of the VI to run on the remote computer
67+
:param control_values: Dictionary of the control values to set on the
68+
target VI
69+
:param run_options: Int to specify the LabVIEW run options for the
70+
target VI
71+
:param open_frontpanel: Boolean that specifies whether to open front
72+
panel of target VI
73+
:param indicator_names: Optional list of strings that specifies the
74+
names of indicators to return. Returns all
75+
indicators if an empty list is specified.
76+
"""
77+
msg = {'command': 'run_vi',
78+
'vi_path': vi_path,
79+
'run_options': run_options,
80+
'open_frontpanel': open_frontpanel,
81+
'control_values': control_values,
82+
'indicator_names': indicator_names}
83+
84+
self._send_dict(msg)
85+
return_vals = self._recv_dict()
86+
self._check_for_error(return_vals)
87+
return return_vals
88+
89+
def describe_error(self, error):
90+
"""
91+
Sends a message to LabVIEW to describe an error.
92+
93+
:param error: Dictionary containing 'source', 'status', and 'code'
94+
"""
95+
msg = {'command': 'describe_error',
96+
'error': error}
97+
self._send_dict(msg)
98+
return_vals = self._recv_dict()
99+
return return_vals['msg']
100+
101+
def set_controls(self, project_path, target_name, vi_path, control_values,
102+
ignore_nonexistent_controls=False):
103+
"""
104+
Sets controls on a VI under a specified target of a specified project
105+
without running the VI. Leaves front panel of the VI open.
106+
107+
:param project_path: Absolute path of the project which contains the VI
108+
to set controls on
109+
:param target_name: Name of the target in the project which contains
110+
the VI to set controls on
111+
:param vi_path: Absolute path of the target VI to set controls on
112+
:param control_values: Dictionary of the control values to set on the
113+
target VI
114+
:param ignore_nonexistent_controls: Boolean that specifies whether to
115+
ignore errors if control_values
116+
contain controls that don't exist
117+
in the target VI
118+
"""
119+
msg = {'command': 'set_controls',
120+
'project_path': project_path,
121+
'target_name': target_name,
122+
'vi_path': vi_path,
123+
'control_values': control_values,
124+
'ignore_nonexistent_controls': ignore_nonexistent_controls}
125+
126+
self._send_dict(msg)
127+
return_vals = self._recv_dict()
128+
self._check_for_error(return_vals)
129+
return return_vals
130+
131+
def get_indicators(self, project_path, target_name,
132+
vi_path, indicator_names):
133+
"""
134+
Get the specified indicators of a VI under a specified target of a
135+
specified project without running the VI.
136+
137+
:param project_path: Absolute path of the project which contains the VI
138+
to get the indicators value
139+
:param target_name: Name of the target in the project which contains
140+
the VI to get the indicators values
141+
:param vi_path: Absolute path of the target VI to get indicators values
142+
:param indicator_names: List of indicator names of which to get values
143+
"""
144+
msg = {'command': 'get_indicators',
145+
'project_path': project_path,
146+
'target_name': target_name,
147+
'vi_path': vi_path,
148+
'indicator_names': indicator_names}
149+
150+
self._send_dict(msg)
151+
return_vals = self._recv_dict()
152+
self._check_for_error(return_vals)
153+
return return_vals
154+
155+
def _recv_dict(self):
156+
if self.connection:
157+
packet_size = self.connection.recv(4)
158+
packet_size_int = struct.unpack('l', packet_size)[0]
159+
# First part of packet will be the 4-byte packet size
160+
packet = packet_size
161+
while len(packet) < packet_size_int:
162+
partial_packet = self.connection.recv(
163+
packet_size_int - len(packet))
164+
if not partial_packet:
165+
break
166+
packet += partial_packet
167+
return bson.decode_all(packet)[0]
168+
169+
def _send_dict(self, msg):
170+
if self.connection:
171+
bson_msg = bson.BSON.encode(msg)
172+
self.connection.send(bson_msg)

0 commit comments

Comments
 (0)