Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 96 additions & 38 deletions src/u12.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,17 @@
low-level.

Most of the UW functions are exposed as functions of the U12 class. With
the exception of the "e" functions, UW functions are Windows only. The "e"
functions will work with both the UW and the Exodriver. Therefore, people
wishing to write cross-platform code should restrict themselves to using
only the "e" functions. The UW functions are described in Section 4 of the
U12 User's Guide:
the exception of the "e" functions, UW functions are Windows only. The
"e" functions will work with both the UW and the Exodriver, as will the
"raw" functions. Therefore, people who want to write cross-platform code
should restrict themselves to using the "e" or "raw" functions. The UW
functions are described in Section 4 of the U12 User's Guide:

http://labjack.com/support/u12/users-guide/4

All low-level functions of the U12 class begin with the word
raw. For example, the low-level function Counter can be called with
U12.rawCounter(). Currently, low-level functions are limited to the
Exodriver (Linux and Mac OS X). You can find descriptions of the low-level
"raw". For example, the low-level function Counter can be called with
U12.rawCounter(). You can find descriptions of the low-level
functions in Section 5 of the U12 User's Guide:

http://labjack.com/support/u12/users-guide/5
Expand Down Expand Up @@ -425,23 +424,26 @@ def __init__(self, id = -1, serialNumber = None, debug = False):
self.handle = None
self.debug = debug
self._autoCloseSetup = False
# USB vendor and product ID
self.vendorID = 0x0CD5
self.productID = 1

if _os_name != "nt":
# Save some variables to save state.
self.pwmAVoltage = 0
self.pwmBVoltage = 0
self.IO3toIO0DirAndStates = BitField(rawByte = 240)

self.open(id, serialNumber)
self.open(id, serialNumber)

def _debugprint(self, msg):
"""Conditionally output msg.

If self.debug is a logging.Logger object, send the msg to it with
DEBUG priority. Otherwise, if self.debug is any truthy, just print
it to stdout.
"""

if self.debug:
if isinstance(self.debug, logging.Logger):
self.debug.debug(msg)
Expand All @@ -453,14 +455,38 @@ def open(self, id = -1, serialNumber = None):
Opens the U12.

The Windows UW driver opens the device every time a function is called.
The Exodriver, however, works like the UD family of devices and returns
a handle. On Windows, this method does nothing. On Mac OS X and Linux,
this method acquires a device handle and saves it to the U12 object.
The Exodriver and "raw" functions work like the UD family of devices
and returns a handle. This method acquires a device handle and saves it
to the U12 object for use with the "raw" functions (and "e" functions
when using macOS or Linux).
"""
self._debugprint("open called")
if _os_name == "nt":
pass
ecode = ctypes.c_long(0)
vID = ctypes.c_uint(self.vendorID) # LabJack USB vendor ID
pID = ctypes.c_uint(self.productID) # U12 product ID
idnum = ctypes.c_long(id)
if serialNumber is None:
serialNumber = 0
serialnum = ctypes.c_long(serialNumber)
numCals = 20
calData =(ctypes.c_long*numCals)(0)
self.handle = staticLib.OpenLabJack(
ctypes.byref(ecode),
vID,
pID,
ctypes.byref(idnum),
ctypes.byref(serialnum),
ctypes.byref(calData)
)
if self.handle is None:
raise U12Exception(
"Couldn't find a U12 with matching open parameters."
)
if ecode.value != 0: raise U12Exception(ecode.value)
self.id = idnum.value
self.serialNumber = serialnum.value
else:
self._debugprint("open called")
devType = ctypes.c_ulong(1)
openDev = staticLib.LJUSB_OpenDevice
openDev.restype = ctypes.c_void_p
Expand Down Expand Up @@ -532,49 +558,81 @@ def open(self, id = -1, serialNumber = None):
raise Exception("Invalid combination of parameters.")


if not self._autoCloseSetup:
# Only need to register auto-close once per device.
atexit.register(self.close)
self._autoCloseSetup = True
if not self._autoCloseSetup:
# Only need to register auto-close once per device.
atexit.register(self.close)
self._autoCloseSetup = True

def close(self):
if _os_name == "nt":
pass
staticLib.CloseAll(self.handle)
else:
staticLib.LJUSB_CloseDevice(self.handle)
self.handle = None
self.handle = None

def write(self, writeBuffer):
if self.handle is None:
raise U12Exception(
"The U12's handle is None. Please open a U12 with open()."
)
self._debugprint("Writing: " + hexWithoutQuotes(writeBuffer))

if _os_name == "nt":
pass
# Windows requires an extra byte at the start
writeBuffer.insert(0,0)
newA = (ctypes.c_ubyte*len(writeBuffer))(0)
for i in range(len(writeBuffer)):
newA[i] = ctypes.c_ubyte(writeBuffer[i])
ecode = staticLib.WriteLabJack(self.handle, ctypes.byref(newA))
if ecode != 0: raise U12Exception(ecode)
writeBuffer.pop(0) # Remove our extra byte from the start
else:
if self.handle is None:
raise U12Exception("The U12's handle is None. Please open a U12 with open().")

self._debugprint("Writing: " + hexWithoutQuotes(writeBuffer))
newA = (ctypes.c_ubyte*len(writeBuffer))(0)
for i in range(len(writeBuffer)):
newA[i] = ctypes.c_ubyte(writeBuffer[i])

writeBytes = staticLib.LJUSB_Write(self.handle, ctypes.byref(newA), len(writeBuffer))

writeBytes = staticLib.LJUSB_Write(
self.handle,
ctypes.byref(newA),
len(writeBuffer)
)
if writeBytes != len(writeBuffer):
raise U12Exception("Could only write %s of %s bytes." % (writeBytes, len(writeBuffer) ) )
raise U12Exception(
"Could only write %s of %s bytes." % \
(writeBytes, len(writeBuffer))
)

return writeBuffer
return writeBuffer

def read(self, numBytes=8, timeout=1000):
if self.handle is None:
raise U12Exception(
"The U12's handle is None. Please open a U12 with open()."
)
if _os_name == "nt":
pass
numBytes+=1 # Windows requires reading an extra byte
newA = (ctypes.c_ubyte*numBytes)()
ecode = staticLib.ReadLabJack(
self.handle,
timeout,
0,
ctypes.byref(newA)
)
if ecode != 0: raise U12Exception(ecode)
# Return a list of integers in command-response mode
# The first byte read must be tossed.
result = [(newA[i] & 0xff) for i in range(1, numBytes)]
else:
if self.handle is None:
raise U12Exception("The U12's handle is None. Please open a U12 with open().")
newA = (ctypes.c_ubyte*numBytes)()
readBytes = staticLib.LJUSB_ReadTO(self.handle, ctypes.byref(newA), numBytes, timeout)
readBytes = staticLib.LJUSB_ReadTO(
self.handle,
ctypes.byref(newA),
numBytes,
timeout
)
# Return a list of integers in command-response mode
result = [(newA[i] & 0xff) for i in range(readBytes)]
self._debugprint("Received: " + hexWithoutQuotes(result))
return result
self._debugprint("Received: " + hexWithoutQuotes(result))
return result

# Low-level helpers
def rawReadSerial(self):
Expand Down