diff --git a/src/u12.py b/src/u12.py index 3afe4ed..ef77d89 100644 --- a/src/u12.py +++ b/src/u12.py @@ -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 @@ -425,6 +424,9 @@ 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. @@ -432,16 +434,16 @@ def __init__(self, id = -1, serialNumber = None, debug = False): 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) @@ -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 @@ -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):