gclib  2.0.8
Communications API for Galil controllers and PLCs
gclib.py
Go to the documentation of this file.
1 '''! \file gclib.py
2 '''
3 """
4 Python wrapper for Galil gclib.
5 Contact softwaresupport@galil.com with questions, comments, and suggestions.
6 """
7 
11 import platform #for distinguishing 'Windows', 'Linux', 'Darwin'
12 from ctypes import *
13 
14 if platform.system() == 'Windows':
15  if '64 bit' in platform.python_compiler():
16  WinDLL(r'C:\Program Files (x86)\Galil\gclib\dll\x64\libcrypto-1_1-x64.dll')
17  WinDLL(r'C:\Program Files (x86)\Galil\gclib\dll\x64\libssl-1_1-x64.dll')
18  _gclib_path = r'C:\Program Files (x86)\Galil\gclib\dll\x64\gclib.dll'
19  _gclibo_path = r'C:\Program Files (x86)\Galil\gclib\dll\x64\gclibo.dll'
20  _gclib = WinDLL(_gclib_path)
21  _gclibo = WinDLL(_gclibo_path)
22  else:
23  WinDLL(r'C:\Program Files (x86)\Galil\gclib\dll\x86\libcrypto-1_1.dll')
24  WinDLL(r'C:\Program Files (x86)\Galil\gclib\dll\x86\libssl-1_1.dll')
25  _gclib_path = r'C:\Program Files (x86)\Galil\gclib\dll\x86\gclib.dll'
26  _gclibo_path = r'C:\Program Files (x86)\Galil\gclib\dll\x86\gclibo.dll'
27  _gclib = WinDLL(_gclib_path)
28  _gclibo = WinDLL(_gclibo_path)
29  #Reassign symbol name, Python doesn't like @ in function names
30  #gclib calls
31  setattr(_gclib, 'GArrayDownload', getattr(_gclib, '_GArrayDownload@20'))
32  setattr(_gclib, 'GArrayUpload', getattr(_gclib, '_GArrayUpload@28'))
33  setattr(_gclib, 'GClose', getattr(_gclib, '_GClose@4'))
34  setattr(_gclib, 'GCommand', getattr(_gclib, '_GCommand@20'))
35  setattr(_gclib, 'GFirmwareDownload', getattr(_gclib, '_GFirmwareDownload@8'))
36  setattr(_gclib, 'GInterrupt', getattr(_gclib, '_GInterrupt@8'))
37  setattr(_gclib, 'GMessage', getattr(_gclib, '_GMessage@12'))
38  setattr(_gclib, 'GOpen', getattr(_gclib, '_GOpen@8'))
39  setattr(_gclib, 'GProgramDownload', getattr(_gclib, '_GProgramDownload@12'))
40  setattr(_gclib, 'GProgramUpload', getattr(_gclib, '_GProgramUpload@12'))
41  #gclibo calls (open source component/convenience functions)
42  setattr(_gclibo, 'GAddresses', getattr(_gclibo, '_GAddresses@8'))
43  setattr(_gclibo, 'GArrayDownloadFile', getattr(_gclibo, '_GArrayDownloadFile@8'))
44  setattr(_gclibo, 'GArrayUploadFile', getattr(_gclibo, '_GArrayUploadFile@12'))
45  setattr(_gclibo, 'GAssign', getattr(_gclibo, '_GAssign@8'))
46  setattr(_gclibo, 'GError', getattr(_gclibo, '_GError@12'))
47  setattr(_gclibo, 'GInfo', getattr(_gclibo, '_GInfo@12'))
48  setattr(_gclibo, 'GIpRequests', getattr(_gclibo, '_GIpRequests@8'))
49  setattr(_gclibo, 'GMotionComplete', getattr(_gclibo, '_GMotionComplete@8'))
50  setattr(_gclibo, 'GProgramDownloadFile', getattr(_gclibo, '_GProgramDownloadFile@12'))
51  setattr(_gclibo, 'GSleep', getattr(_gclibo, '_GSleep@4'))
52  setattr(_gclibo, 'GProgramUploadFile', getattr(_gclibo, '_GProgramUploadFile@8'))
53  setattr(_gclibo, 'GTimeout', getattr(_gclibo, '_GTimeout@8'))
54  setattr(_gclibo, 'GVersion', getattr(_gclibo, '_GVersion@8'))
55  setattr(_gclibo, 'GSetupDownloadFile', getattr(_gclibo, '_GSetupDownloadFile@20'))
56  setattr(_gclibo, 'GServerStatus', getattr(_gclibo, '_GServerStatus@8'))
57  setattr(_gclibo, 'GSetServer', getattr(_gclibo, '_GSetServer@4'))
58  setattr(_gclibo, 'GListServers', getattr(_gclibo, '_GListServers@8'))
59  setattr(_gclibo, 'GPublishServer', getattr(_gclibo, '_GPublishServer@12'))
60  setattr(_gclibo, 'GRemoteConnections', getattr(_gclibo, '_GRemoteConnections@8'))
61 
62 elif platform.system() == 'Linux':
63  cdll.LoadLibrary("libgclib.so.2")
64  _gclib = CDLL("libgclib.so.2")
65  cdll.LoadLibrary("libgclibo.so.2")
66  _gclibo = CDLL("libgclibo.so.2")
67 
68 elif platform.system() == 'Darwin': #OSX
69  _gclib_path = '/Applications/gclib/dylib/gclib.0.dylib'
70  _gclibo_path = '/Applications/gclib/dylib/gclibo.0.dylib'
71  cdll.LoadLibrary(_gclib_path)
72  _gclib = CDLL(_gclib_path)
73  cdll.LoadLibrary(_gclibo_path)
74  _gclibo = CDLL(_gclibo_path)
75 
76 
77 
78 # Python "typedefs"
79 _GReturn = c_int #type for a return code
80 _GCon = c_void_p #type for a Galil connection handle
81 _GCon_ptr = POINTER(_GCon) #used for argtypes declaration
82 _GSize = c_ulong #type for a Galil size variable
83 _GSize_ptr = POINTER(_GSize) #used for argtypes declaration
84 _GCStringIn = c_char_p #char*. In C it's const.
85 _GCStringOut = c_char_p #char*
86 _GOption = c_int #type for option variables, e.g. GArrayDownload
87 _GStatus = c_ubyte #type for interrupt status bytes
88 _GStatus_ptr = POINTER(_GStatus) #used for argtypes declaration
89 
90 #Define arguments and result type (if not C int type)
91 #gclib calls
92 _gclib.GArrayDownload.argtypes = [_GCon, _GCStringIn, _GOption, _GOption, _GCStringIn]
93 _gclib.GArrayUpload.argtypes = [_GCon, _GCStringIn, _GOption, _GOption, _GOption, _GCStringOut, _GSize]
94 _gclib.GClose.argtypes = [_GCon]
95 _gclib.GCommand.argtypes = [_GCon, _GCStringIn, _GCStringOut, _GSize, _GSize_ptr]
96 _gclib.GFirmwareDownload.argtypes = [_GCon, _GCStringIn]
97 _gclib.GInterrupt.argtypes = [_GCon, _GStatus_ptr]
98 _gclib.GMessage.argtypes = [_GCon, _GCStringOut, _GSize]
99 _gclib.GOpen.argtypes = [_GCStringIn, _GCon_ptr]
100 _gclib.GProgramDownload.argtypes = [_GCon, _GCStringIn, _GCStringIn]
101 _gclib.GProgramUpload.argtypes = [_GCon, _GCStringOut, _GSize]
102 #gclibo calls (open source component/convenience functions)
103 _gclibo.GAddresses.argtypes = [_GCStringOut, _GSize]
104 _gclibo.GArrayDownloadFile.argtypes = [_GCon, _GCStringIn]
105 _gclibo.GArrayUploadFile.argtypes = [_GCon, _GCStringIn, _GCStringIn]
106 _gclibo.GAssign.argtypes = [_GCStringIn, _GCStringIn]
107 _gclibo.GError.argtypes = [_GReturn, _GCStringOut, _GSize]
108 _gclibo.GError.restype = None
109 _gclibo.GError.argtypes = [_GCon, _GCStringOut, _GSize]
110 _gclibo.GIpRequests.argtypes = [_GCStringOut, _GSize]
111 _gclibo.GMotionComplete.argtypes = [_GCon, _GCStringIn]
112 _gclibo.GProgramDownloadFile.argtypes = [_GCon, _GCStringIn, _GCStringIn]
113 _gclibo.GSleep.argtypes = [c_uint]
114 _gclibo.GSleep.restype = None
115 _gclibo.GProgramUploadFile.argtypes = [_GCon, _GCStringIn]
116 _gclibo.GTimeout.argtypes = [_GCon, c_int]
117 _gclibo.GVersion.argtypes = [_GCStringOut, _GSize]
118 _gclibo.GServerStatus.argtypes = [_GCStringOut, _GSize]
119 _gclibo.GSetServer.argtypes = [_GCStringIn]
120 _gclibo.GListServers.argtypes = [_GCStringOut, _GSize]
121 _gclibo.GPublishServer.argtypes = [_GCStringIn, _GOption, _GOption]
122 _gclibo.GRemoteConnections.argtypes = [_GCStringOut, _GSize]
123 _gclibo.GSetupDownloadFile.argtypes = [_GCon, _GCStringIn, _GOption, _GCStringOut, _GSize]
124 
125 #Set up some constants
126 _enc = "ASCII" #byte encoding for going between python strings and c strings.
127 _buf_size = 500000 #size of response buffer. Big enough to fit entire 4000 program via UL/LS, or 24000 elements of array data.
128 _error_buf = create_string_buffer(128) #buffer for retrieving error code descriptions.
129 
130 def _rc(return_code):
131  """Checks return codes from gclib and raises a python error if result is exceptional."""
132  if return_code != 0:
133  _gclibo.GError(return_code, _error_buf, 128) #Get the library's error description
134  raise GclibError(str(_error_buf.value.decode(_enc)))
135  return
136 
137 class GclibError(Exception):
138  """Error class for non-zero gclib return codes."""
139  pass
140 
141 class py:
142  """Represents a single Python connection to a Galil Controller or PLC."""
143 
144  def __init__(self):
145  """Constructor for the Connection class. Initializes gclib's handle and read buffer."""
146  self._gcon_gcon = _GCon(0) #handle to connection
147  self._buf_buf = create_string_buffer(_buf_size)
148  self._timeout_timeout = 5000
149  return
150 
151  def __del__(self):
152  """Destructor for the Connection class. Ensures close gets called to release Galil resource (Sockets, Kernel Driver, Com Port, etc)."""
153  self.GCloseGClose()
154  return
155 
156  def _cc(self):
157  """Checks if connection is established, throws error if not."""
158  if self._gcon_gcon.value == None:
159  _rc(-1201) #G_CONNECTION_NOT_ESTABLISHED
160 
161  def GOpen(self, address):
162  """
163  Opens a connection a galil controller.
164  See the gclib docs for address string formatting.
165  """
166  c_address = _GCStringIn(address.encode(_enc))
167  _rc(_gclib.GOpen(c_address, byref(self._gcon_gcon)))
168  return
169 
170 
171  def GClose(self):
172  """
173  Closes a connection to a Galil Controller.
174  """
175  if self._gcon_gcon.value != None:
176  _rc(_gclib.GClose(self._gcon_gcon))
177  self._gcon_gcon = _GCon(0)
178  return
179 
180 
181  def GCommand(self, command):
182  """
183  Performs a command-and-response transaction on the connection.
184  Trims the response.
185  """
186  self._cc_cc()
187  c_command = _GCStringIn(command.encode(_enc))
188  _rc(_gclib.GCommand(self._gcon_gcon, c_command, self._buf_buf, _buf_size, None))
189  response = str(self._buf_buf.value.decode(_enc))
190  return response[:-3].strip() # trim trailing /r/n: and leading space
191 
192 
193  def GSleep(self, val):
194  """
195  Provides a blocking sleep call which can be useful for timing-based chores.
196  """
197  _gclibo.GSleep(val)
198  return
199 
200 
201  def GVersion(self):
202  """
203  Provides the gclib version number. Please include the output of this function on all support cases.
204  """
205  _rc(_gclibo.GVersion(self._buf_buf, _buf_size))
206  return "py." + str(self._buf_buf.value.decode(_enc))
207 
208  def GServerStatus(self):
209  _rc(_gclibo.GServerStatus(self._buf_buf, _buf_size))
210  return str(self._buf_buf.value.decode(_enc))
211 
212  def GSetServer(self, server_name):
213  c_server_name = _GCStringIn(server_name.encode(_enc))
214  _rc(_gclibo.GSetServer(c_server_name))
215  return
216 
217  def GListServers(self):
218  _rc(_gclibo.GListServers(self._buf_buf, _buf_size))
219  return str(self._buf_buf.value.decode(_enc))
220 
221  def GPublishServer(self, server_name, publish, save):
222  c_server_name = _GCStringIn(server_name.encode(_enc))
223  _rc(_gclibo.GPublishServer(c_server_name, publish, save))
224  return
225 
226  def GRemoteConnections(self):
227  _rc(_gclibo.GRemoteConnections(self._buf_buf, _buf_size))
228  return str(self._buf_buf.value.decode(_enc))
229 
230  def GInfo(self):
231  """
232  Provides a useful connection string. Please include the output of this function on all support cases.
233  """
234  _rc(_gclibo.GInfo(self._gcon_gcon, self._buf_buf, _buf_size))
235  return str(self._buf_buf.value.decode(_enc))
236 
237 
238  def GIpRequests(self):
239  """
240  Provides a dictionary of all Galil controllers requesting IP addresses via BOOT-P or DHCP.
241 
242  Returns a dictionary mapping 'model-serial' --> 'mac address'
243  e.g. {'DMC4000-783': '00:50:4c:20:03:0f', 'DMC4103-9998': '00:50:4c:38:27:0e'}
244 
245  Linux/OS X users must be root to use GIpRequests() and have UDP access to bind and listen on port 67.
246  """
247  _rc(_gclibo.GIpRequests(self._buf_buf, _buf_size)) #get the c string from gclib
248  ip_req_dict = {}
249  for line in str(self._buf_buf.value.decode(_enc)).splitlines():
250  line = line.replace(' ', '') #trim spaces throughout
251  if (line == ""): continue
252  fields = line.split(',')
253  #fields go [model, serial number, mac]
254  ip_req_dict[fields[0] + '-' + fields[1]] = fields[2] # e.g. DMC4000-783 maps to its MAC addr.
255  return ip_req_dict
256 
257 
258  def GAssign(self, ip, mac):
259  """
260  Assigns IP address over the Ethernet to a controller at a given MAC address.
261  Linux/OS X users must be root to use GAssign() and have UDP access to send on port 68.
262  """
263  c_ip = _GCStringIn(ip.encode(_enc))
264  c_mac = _GCStringIn(mac.encode(_enc))
265  _rc(_gclibo.GAssign(c_ip, c_mac))
266  return
267 
268 
269  def GAddresses(self):
270  """
271  Provides a dictionary of all available connection addresses.
272 
273  Returns a dictionary mapping 'address' -> 'revision reports', where possible
274  e.g. {}
275  """
276  _rc(_gclibo.GAddresses(self._buf_buf, _buf_size))
277  addr_dict = {}
278  for line in str(self._buf_buf.value.decode(_enc)).splitlines():
279  fields = line.split(',')
280  if len(fields) >= 2:
281  addr_dict[fields[0]] = fields[1]
282  else:
283  addr_dict[fields[0]] = ''
284 
285  return addr_dict
286 
287 
288  def GProgramDownload(self, program, preprocessor=""):
289  """
290  Downloads a program to the controller's program buffer.
291  See the gclib docs for preprocessor options.
292  """
293  self._cc_cc()
294  c_prog = _GCStringIn(program.encode(_enc))
295  c_pre = _GCStringIn(preprocessor.encode(_enc))
296  _rc(_gclib.GProgramDownload(self._gcon_gcon, c_prog, c_pre))
297  return
298 
299 
300  def GProgramUpload(self):
301  """
302  Uploads a program from the controller's program buffer.
303  """
304  self._cc_cc()
305  _rc(_gclib.GProgramUpload(self._gcon_gcon, self._buf_buf, _buf_size))
306  return str(self._buf_buf.value.decode(_enc))
307 
308 
309  def GProgramDownloadFile(self, file_path, preprocessor=""):
310  """
311  Program download from file.
312  See the gclib docs for preprocessor options.
313  """
314  self._cc_cc()
315  c_path = _GCStringIn(file_path.encode(_enc))
316  c_pre = _GCStringIn(preprocessor.encode(_enc))
317  _rc(_gclibo.GProgramDownloadFile(self._gcon_gcon, c_path, c_pre))
318  return
319 
320  def GProgramUploadFile(self, file_path):
321  """
322  Program upload to file.
323  """
324  self._cc_cc()
325  c_path = _GCStringIn(file_path.encode(_enc))
326  _rc(_gclibo.GProgramUploadFile(self._gcon_gcon, c_path))
327  return
328 
329  def GArrayDownload(self, name, first, last, array_data):
330  """
331  Downloads array data to a pre-dimensioned array in the controller's array table.
332  array_data should be a list of values (e.g. int or float)
333  """
334  self._cc_cc()
335  c_name = _GCStringIn(name.encode(_enc))
336  array_string = ""
337  for val in array_data:
338  array_string += str(val) + ","
339  c_data = _GCStringIn(array_string[:-1].encode(_enc)) #trim trailing command
340  _rc(_gclib.GArrayDownload(self._gcon_gcon, c_name, first, last, c_data))
341  return
342 
343 
344  def GArrayUploadFile(self, file_path, names = []):
345  """
346  Uploads the entire controller array table or a subset and saves the data as a csv file specified by file_path.
347  names is optional and should be a list of array names on the controller.
348  """
349  self._cc_cc()
350  c_path = _GCStringIn(file_path.encode(_enc))
351  names_string = ''
352  c_names = _GCStringIn(''.encode(_enc)) #in case empty list provided
353  for name in names:
354  names_string += name + ' '
355 
356  c_names = _GCStringIn(names_string[:-1].encode(_enc)) #trim trailing space
357  _rc(_gclibo.GArrayUploadFile(self._gcon_gcon, c_path, c_names))
358  return
359 
360 
361  def GArrayDownloadFile(self, file_path):
362  """
363  Downloads a csv file containing array data at file_path.
364  """
365  self._cc_cc()
366  c_path = _GCStringIn(file_path.encode(_enc))
367  _rc(_gclibo.GArrayDownloadFile(self._gcon_gcon, c_path))
368  return
369 
370 
371  def GArrayUpload(self, name, first, last):
372  """
373  Uploads array data from the controller's array table.
374  """
375  self._cc_cc()
376  c_name = _GCStringIn(name.encode(_enc))
377  _rc(_gclib.GArrayUpload(self._gcon_gcon, c_name, first, last, 1, self._buf_buf, _buf_size)) #1 is comma delimiter
378  string_list = str(self._buf_buf.value.decode(_enc)).split(',')
379  float_list = []
380  for s in string_list:
381  float_list.append(float(s))
382  return float_list
383 
384 
385  def GTimeout(self, timeout):
386  """
387  Set the library timeout. Set to -1 to use the intitial library timeout, as specified in GOpen.
388  """
389  self._cc_cc()
390  _rc(_gclibo.GTimeout(self._gcon_gcon, timeout))
391  self._timeout_timeout = timeout
392  return
393 
394 
395  @property
396  def timeout(self):
397  """
398  Convenience property read access to timeout value. If -1, gclib uses the initial library timeout, as specified in GOpen.
399  """
400  return self._timeout_timeout
401 
402  @timeout.setter
403  def timeout(self, timeout):
404  """
405  Convenience property write access to timeout value. Set to -1 to use the initial library timeout, as specified in GOpen.
406  """
407  self.GTimeoutGTimeout(timeout)
408  return
409 
410 
411  def GFirmwareDownload(self, file_path):
412  """
413  Upgrade firmware.
414  """
415  self._cc_cc()
416  c_path = _GCStringIn(file_path.encode(_enc))
417  _rc(_gclib.GFirmwareDownload(self._gcon_gcon, c_path))
418  return
419 
420 
421  def GMessage(self):
422  """
423  Provides access to unsolicited messages from the controller.
424  """
425  self._cc_cc()
426  _rc(_gclib.GMessage(self._gcon_gcon, self._buf_buf, _buf_size))
427  return str(self._buf_buf.value.decode(_enc))
428 
429 
430  def GMotionComplete(self, axes):
431  """
432  Blocking call that returns once all axes specified have completed their motion.
433  """
434  self._cc_cc()
435  c_axes = _GCStringIn(axes.encode(_enc))
436  _rc(_gclibo.GMotionComplete(self._gcon_gcon, c_axes))
437  return
438 
439  def GInterrupt(self):
440  """
441  Provides access to PCI and UDP interrupts from the controller.
442  """
443  self._cc_cc()
444  status = _GStatus(0)
445  _rc(_gclib.GInterrupt(self._gcon_gcon, byref(status)))
446  return status.value
447 
448  def GSetupDownloadFile(self, file_path, options):
449  """
450  Downloads specified sectors from a Galil compressed backup (gcb) file to a controller.
451 
452  Returns a dictionary with the controller information stored in the gcb file.
453  If options is specified as 0, an additional "options" key will be in the dictionary indicating the info sectors available in the gcb
454  """
455  self._cc_cc()
456  c_path = _GCStringIn(file_path.encode(_enc))
457 
458  rc = _gclibo.GSetupDownloadFile(self._gcon_gcon, c_path, options, self._buf_buf, _buf_size)
459  if (options != 0):
460  _rc(rc)
461 
462  info_dict = {}
463  for line in str(self._buf_buf.value.decode(_enc)).split("\"\n"):
464  fields = line.split(',',1)
465 
466  if (fields[0] == ""): continue
467  elif len(fields) >= 2:
468  info_dict[fields[0].strip("\"\'")] = fields[1].strip("\"\'")
469  else:
470  info_dict[fields[0].strip("\"\'")] = ''
471 
472  if (options == 0):
473  info_dict["options"] = rc
474 
475  return info_dict
def GInterrupt(self)
Definition: gclib.py:439
def GFirmwareDownload(self, file_path)
Definition: gclib.py:411
def GMotionComplete(self, axes)
Definition: gclib.py:430
def GProgramDownload(self, program, preprocessor="")
Definition: gclib.py:288
def GProgramDownloadFile(self, file_path, preprocessor="")
Definition: gclib.py:309
def GTimeout(self, timeout)
Definition: gclib.py:385
def GOpen(self, address)
Definition: gclib.py:161
def GArrayUploadFile(self, file_path, names=[])
Definition: gclib.py:344
def timeout(self)
Definition: gclib.py:396
def GArrayDownloadFile(self, file_path)
Definition: gclib.py:361
def GCommand(self, command)
Definition: gclib.py:181
def __del__(self)
Definition: gclib.py:151
def GAddresses(self)
Definition: gclib.py:269
def GProgramUploadFile(self, file_path)
Definition: gclib.py:320
def GArrayUpload(self, name, first, last)
Definition: gclib.py:371
def GProgramUpload(self)
Definition: gclib.py:300
def GArrayDownload(self, name, first, last, array_data)
Definition: gclib.py:329
def GMessage(self)
Definition: gclib.py:421
def GSleep(self, val)
Definition: gclib.py:193
def GSetupDownloadFile(self, file_path, options)
Definition: gclib.py:448
def GVersion(self)
Definition: gclib.py:201
def GAssign(self, ip, mac)
Definition: gclib.py:258
def GClose(self)
Definition: gclib.py:171
def __init__(self)
Definition: gclib.py:144
def GInfo(self)
Definition: gclib.py:230
def GIpRequests(self)
Definition: gclib.py:238
_timeout
Definition: gclib.py:148
def _cc(self)
Definition: gclib.py:156