Created
March 10, 2011 03:15
-
-
Save bglusman/863520 to your computer and use it in GitHub Desktop.
labjack project
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#simple loop to toggle LED on and off forever | |
import time | |
import math | |
import ConfigParser | |
import logging | |
LEVELS = {'debug' : logging.DEBUG, | |
'info' : logging.INFO, | |
'warning' : logging.WARNING, | |
'error' : logging.ERROR, | |
'critical': logging.CRITICAL} | |
MajorPeriod = 1 | |
MinorPeriod = .5 | |
LED = 6004 | |
Log_Filename = "incline.log" | |
Log_Level = "info" | |
#Initilize Labjack | |
import u3 | |
Device = u3.U3(autoOpen = False) | |
# LED state: null = false = led off | |
State = () | |
#set an initial Target time for first iteration and round up to a whole second | |
Target = math.ceil(time.time()) | |
while 1 != 0: | |
Start = time.time() | |
# | |
#read config file and set default values. default values don't work as intended. | |
# | |
config = ConfigParser.RawConfigParser() | |
config.read('config.file') | |
#read config file into temporary variables | |
New_LED = config.getint('section 1', 'LED address') | |
New_MajorPeriod = config.getfloat('section 1', 'MajorPeriod') | |
New_MinorPeriod = config.getfloat('section 1', 'MinorPeriod') | |
New_level_name = config.get('section 1', 'LogLevel') | |
New_Log_Filename = config.get('section 1', 'LogFile') | |
#test for change in log name and level. has to be done here to get looging going. | |
old_log_name = () | |
if Log_Filename != New_Log_Filename: | |
old_log_name = 1 | |
Log_Filename = New_Log_Filename | |
#this doesn't work correctly because the names are mapped to numeric values. | |
# old_log_level = () | |
if New_level_name != Log_Level: | |
# old_log_level = 1 | |
Log_Level = New_level_name | |
#configure logging | |
Log_Level = LEVELS.get(Log_Level, logging.NOTSET) | |
logging.basicConfig(filename=Log_Filename,level=Log_Level) | |
#log any changes to log name and level | |
if old_log_name: | |
logging.info('Logfile set to:') | |
# if old_log_level: | |
# logging.info('Log level set to:') | |
#test if other parameters have changed vs new values from file. if yes then log and update dictionary. | |
if New_LED != LED: | |
logging.info('LED address set to:') | |
LED = New_LED | |
if New_MajorPeriod != MajorPeriod: | |
logging.info('Major Period set to:') | |
MajorPeriod = New_MajorPeriod | |
if New_MinorPeriod != MinorPeriod: | |
logging.info('Minor Period set to:') | |
MinorPeriod = New_MinorPeriod | |
#calculate time to sleep | |
NapTime = MajorPeriod/MinorPeriod | |
# round Target up to nearest even time | |
Overplus = Target % MajorPeriod | |
if Overplus != 0: | |
Target = Target + ( MajorPeriod - Overplus ) | |
if Start >= Target: | |
logging.debug('This message should go to the log file') | |
Target = Target + MajorPeriod | |
#initialize labjack on each loop | |
Device.open() | |
#flip current state | |
State = not State | |
print "LED is %s" % State | |
#toggle the LED | |
Device.writeRegister(LED, State) | |
#close the labjack on eachloop | |
Device.close() | |
else: | |
Remainder = Target - Start | |
if Remainder < NapTime: | |
time.sleep(Remainder) | |
else: | |
#Minor Period | |
#preforms actions? | |
time.sleep(NapTime) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Name: u3.py | |
Desc: Defines the U3 class, which makes working with a U3 much easier. All of | |
the low-level functions for the U3 are implemented as functions of the U3 | |
class. There are also a handful additional functions which improve upon | |
the interface provided by the low-level functions. | |
To learn about the low-level functions, please see Section 5.2 of the U3 User's Guide: | |
http://labjack.com/support/u3/users-guide/5.2 | |
Section Number Mapping: | |
1 = Object Functions | |
2 = User's Guide Functions | |
3 = Convenience Functions | |
4 = Private Helper Functions | |
""" | |
from LabJackPython import * | |
import struct, ConfigParser | |
FIO0, FIO1, FIO2, FIO3, FIO4, FIO5, FIO6, FIO7, \ | |
EIO0, EIO1, EIO2, EIO3, EIO4, EIO5, EIO6, EIO7, \ | |
CIO0, CIO1, CIO2, CIO3 = range(20) | |
def openAllU3(): | |
""" | |
A helpful function which will open all the connected U3s. Returns a | |
dictionary where the keys are the serialNumber, and the value is the device | |
object. | |
""" | |
returnDict = dict() | |
for i in range(deviceCount(3)): | |
d = U3(firstFound = False, devNumber = i+1) | |
returnDict[str(d.serialNumber)] = d | |
return returnDict | |
class U3(Device): | |
""" | |
U3 Class for all U3 specific low-level commands. | |
Example: | |
>>> import u3 | |
>>> d = u3.U3() | |
>>> print d.configU3() | |
{'SerialNumber': 320032102, ... , 'FirmwareVersion': '1.26'} | |
""" | |
def __init__(self, debug = False, autoOpen = True, **kargs): | |
""" | |
Name: U3.__init__(debug = False, autoOpen = True, **openArgs) | |
Args: debug, enables debug output | |
autoOpen, if true, the class will try to open a U3 using openArgs | |
**openArgs, the arguments to pass to the open call. See U3.open() | |
Desc: Instantiates a new U3 object. If autoOpen == True, then it will | |
also open a U3. | |
Examples: | |
Simplest: | |
>>> import u3 | |
>>> d = u3.U3() | |
For debug output: | |
>>> import u3 | |
>>> d = u3.U3(debug = True) | |
To open a U3 with Local ID = 2: | |
>>> import u3 | |
>>> d = u3.U3(localId = 2) | |
""" | |
Device.__init__(self, None, devType = 3) | |
self.debug = debug | |
self.calData = None | |
self.ledState = True | |
if autoOpen: | |
self.open(**kargs) | |
__init__.section = 1 | |
def open(self, firstFound = True, serial = None, localId = None, devNumber = None, handleOnly = False, LJSocket = None): | |
""" | |
Name: U3.open(firstFound = True, localId = None, devNumber = None, | |
handleOnly = False, LJSocket = None) | |
Args: firstFound, If True, use the first found U3 | |
serial, open a U3 with the given serial number | |
localId, open a U3 with the given local id. | |
devNumber, open a U3 with the given devNumber | |
handleOnly, if True, LabJackPython will only open a handle | |
LJSocket, set to "<ip>:<port>" to connect to LJSocket | |
Desc: Use to open a U3. If handleOnly is false, it will call configU3 | |
and save the resulting information to the object. This allows the | |
use of d.serialNumber, d.firmwareVersion, etc. | |
Examples: | |
Simplest: | |
>>> import u3 | |
>>> d = u3.U3(autoOpen = False) | |
>>> d.open() | |
Handle-only, with a serial number = 320095789: | |
>>> import u3 | |
>>> d = u3.U3(autoOpen = False) | |
>>> d.open(handleOnly = True, serial = 320095789) | |
Using LJSocket: | |
>>> import u3 | |
>>> d = u3.U3(autoOpen = False) | |
>>> d.open(LJSocket = "localhost:6000") | |
""" | |
Device.open(self, 3, firstFound = firstFound, serial = serial, localId = localId, devNumber = devNumber, handleOnly = handleOnly, LJSocket = LJSocket ) | |
open.section = 1 | |
def configU3(self, LocalID = None, TimerCounterConfig = None, FIOAnalog = None, FIODirection = None, FIOState = None, EIOAnalog = None, EIODirection = None, EIOState = None, CIODirection = None, CIOState = None, DAC1Enable = None, DAC0 = None, DAC1 = None, TimerClockConfig = None, TimerClockDivisor = None, CompatibilityOptions = None ): | |
""" | |
Name: U3.configU3(LocalID = None, TimerCounterConfig = None, FIOAnalog = None, FIODirection = None, FIOState = None, EIOAnalog = None, EIODirection = None, EIOState = None, CIODirection = None, CIOState = None, DAC1Enable = None, DAC0 = None, DAC1 = None, TimerClockConfig = None, TimerClockDivisor = None, CompatibilityOptions = None) | |
Args: See section 5.2.2 of the users guide. | |
Desc: Sends the low-level configU3 command. Also saves relevant | |
information to the U3 object for later use. | |
Example: | |
Simplest: | |
>>> import u3 | |
>>> d = u3.U3() | |
>>> print d.configU3() | |
{ | |
'LocalID': 1, | |
'SerialNumber': 320035782, | |
'DeviceName': 'U3-LV', | |
'FIODirection': 0, | |
'FirmwareVersion': '1.24', | |
... , | |
'ProductID': 3 | |
} | |
Configure all FIOs and EI0s to analog on boot: | |
>>> import u3 | |
>>> d = u3.U3() | |
>>> print d.configU3( FIOAnalog = 255, EIOAnalog = 255) | |
{ | |
'FIOAnalog': 255, | |
'EIOAnalog': 255, | |
... , | |
'ProductID': 3 | |
} | |
""" | |
writeMask = 0 | |
if FIOAnalog is not None or FIODirection is not None or FIOState is not None or EIOAnalog is not None or EIODirection is not None or EIOState is not None or CIODirection is not None or CIOState is not None: | |
writeMask |= 2 | |
if DAC1Enable is not None or DAC0 is not None or DAC1 is not None: | |
writeMask |= 4 | |
if LocalID is not None: | |
writeMask |= 8 | |
command = [ 0 ] * 26 | |
#command[0] = Checksum8 | |
command[1] = 0xF8 | |
command[2] = 0x0A | |
command[3] = 0x08 | |
#command[4] = Checksum16 (LSB) | |
#command[5] = Checksum16 (MSB) | |
command[6] = writeMask | |
#command[7] = WriteMask1 | |
if LocalID is not None: | |
command[8] = LocalID | |
if TimerCounterConfig is not None: | |
command[9] = TimerCounterConfig | |
if FIOAnalog is not None: | |
command[10] = FIOAnalog | |
if FIODirection is not None: | |
command[11] = FIODirection | |
if FIOState is not None: | |
command[12] = FIOState | |
if EIOAnalog is not None: | |
command[13] = EIOAnalog | |
if EIODirection is not None: | |
command[14] = EIODirection | |
if EIOState is not None: | |
command[15] = EIOState | |
if CIODirection is not None: | |
command[16] = CIODirection | |
if CIOState is not None: | |
command[17] = CIOState | |
if DAC1Enable is not None: | |
command[18] = DAC1Enable | |
if DAC0 is not None: | |
command[19] = DAC0 | |
if DAC1 is not None: | |
command[20] = DAC1 | |
if TimerClockConfig is not None: | |
command[21] = TimerClockConfig | |
if TimerClockDivisor is not None: | |
command[22] = TimerClockDivisor | |
if CompatibilityOptions is not None: | |
command[23] = CompatibilityOptions | |
result = self._writeRead(command, 38, [0xF8, 0x10, 0x08]) | |
# Error-free, time to parse the response | |
self.firmwareVersion = "%d.%02d" % (result[10], result[9]) | |
self.bootloaderVersion = "%d.%02d" % (result[12], result[11]) | |
self.hardwareVersion = "%d.%02d" % (result[14], result[13]) | |
self.serialNumber = struct.unpack("<I", struct.pack(">BBBB", *result[15:19]))[0] | |
self.productId = struct.unpack("<H", struct.pack(">BB", *result[19:21]))[0] | |
self.localId = result[21] | |
self.timerCounterMask = result[22] | |
self.fioAnalog = result[23] | |
self.fioDirection = result[24] | |
self.fioState = result[25] | |
self.eioAnalog = result[26] | |
self.eioDirection = result[27] | |
self.eioState = result[28] | |
self.cioDirection = result[29] | |
self.cioState = result[30] | |
self.dac1Enable = result[31] | |
self.dac0 = result[32] | |
self.dac1 = result[33] | |
self.timerClockConfig = result[34] | |
self.timerClockDivisor = result[35] | |
if result[35] == 0: | |
self.timerClockDivisor = 256 | |
self.compatibilityOptions = result[36] | |
self.versionInfo = result[37] | |
self.deviceName = 'U3' | |
if self.versionInfo == 1: | |
self.deviceName += 'B' | |
elif self.versionInfo == 2: | |
self.deviceName += '-LV' | |
elif self.versionInfo == 18: | |
self.deviceName += '-HV' | |
return { 'FirmwareVersion' : self.firmwareVersion, 'BootloaderVersion' : self.bootloaderVersion, 'HardwareVersion' : self.hardwareVersion, 'SerialNumber' : self.serialNumber, 'ProductID' : self.productId, 'LocalID' : self.localId, 'TimerCounterMask' : self.timerCounterMask, 'FIOAnalog' : self.fioAnalog, 'FIODirection' : self.fioDirection, 'FIOState' : self.fioState, 'EIOAnalog' : self.eioAnalog, 'EIODirection' : self.eioDirection, 'EIOState' : self.eioState, 'CIODirection' : self.cioDirection, 'CIOState' : self.cioState, 'DAC1Enable' : self.dac1Enable, 'DAC0' : self.dac0, 'DAC1' : self.dac1, 'TimerClockConfig' : self.timerClockConfig, 'TimerClockDivisor' : self.timerClockDivisor, 'CompatibilityOptions' : self.compatibilityOptions, 'VersionInfo' : self.versionInfo, 'DeviceName' : self.deviceName } | |
configU3.section = 2 | |
def configIO(self, TimerCounterPinOffset = None, EnableCounter1 = None, EnableCounter0 = None, NumberOfTimersEnabled = None, FIOAnalog = None, EIOAnalog = None, EnableUART = None): | |
""" | |
Name: U3.configIO(TimerCounterPinOffset = 4, EnableCounter1 = None, EnableCounter0 = None, NumberOfTimersEnabled = None, FIOAnalog = None, EIOAnalog = None, EnableUART = None) | |
Args: See section 5.2.3 of the user's guide. | |
Desc: The configIO command. | |
Examples: | |
Simplest: | |
>>> import u3 | |
>>> d = u3.U3() | |
>>> print d.configIO() | |
{ | |
'NumberOfTimersEnabled': 0, | |
'TimerCounterPinOffset': 4, | |
'DAC1Enable': 0, | |
'FIOAnalog': 239, | |
'EIOAnalog': 0, | |
'TimerCounterConfig': 64, | |
'EnableCounter1': False, | |
'EnableCounter0': False | |
} | |
Set all FIOs and EIOs to digital (until power cycle): | |
>>> import u3 | |
>>> d = u3.U3() | |
>>> print d.configIO(FIOAnalog = 0, EIOAnalog = 0) | |
{ | |
'NumberOfTimersEnabled': 0, | |
'TimerCounterPinOffset': 4, | |
'DAC1Enable': 0, | |
'FIOAnalog': 0, | |
'EIOAnalog': 0, | |
'TimerCounterConfig': 64, | |
'EnableCounter1': False, | |
'EnableCounter0': False | |
} | |
""" | |
writeMask = 0 | |
if EIOAnalog is not None: | |
writeMask |= 1 | |
writeMask |= 8 | |
if FIOAnalog is not None: | |
writeMask |= 1 | |
writeMask |= 4 | |
if EnableUART is not None: | |
writeMask |= 1 | |
writeMask |= (1 << 5) | |
if TimerCounterPinOffset is not None or EnableCounter1 is not None or EnableCounter0 is not None or NumberOfTimersEnabled is not None : | |
writeMask |= 1 | |
command = [ 0 ] * 12 | |
#command[0] = Checksum8 | |
command[1] = 0xF8 | |
command[2] = 0x03 | |
command[3] = 0x0B | |
#command[4] = Checksum16 (LSB) | |
#command[5] = Checksum16 (MSB) | |
command[6] = writeMask | |
#command[7] = Reserved | |
command[8] = 0 | |
if EnableUART is not None: | |
command[9] = int(EnableUART) << 2 | |
if TimerCounterPinOffset is None: | |
command[8] |= ( 4 & 15 ) << 4 | |
else: | |
command[8] |= ( TimerCounterPinOffset & 15 ) << 4 | |
if EnableCounter1 is not None: | |
command[8] |= 1 << 3 | |
if EnableCounter0 is not None: | |
command[8] |= 1 << 2 | |
if NumberOfTimersEnabled is not None: | |
command[8] |= ( NumberOfTimersEnabled & 3 ) | |
if FIOAnalog is not None: | |
command[10] = FIOAnalog | |
if EIOAnalog is not None: | |
command[11] = EIOAnalog | |
result = self._writeRead(command, 12, [0xF8, 0x03, 0x0B]) | |
self.timerCounterConfig = result[8] | |
self.numberTimersEnabled = self.timerCounterConfig & 3 | |
self.counter0Enabled = bool( (self.timerCounterConfig >> 2) & 1 ) | |
self.counter1Enabled = bool( (self.timerCounterConfig >> 3) & 1 ) | |
self.timerCounterPinOffset = ( self.timerCounterConfig >> 4 ) | |
self.dac1Enable = result[9] | |
self.fioAnalog = result[10] | |
self.eioAnalog = result[11] | |
return { 'TimerCounterConfig' : self.timerCounterConfig, 'DAC1Enable' : self.dac1Enable, 'FIOAnalog' : self.fioAnalog, 'EIOAnalog' : self.eioAnalog, 'NumberOfTimersEnabled' : self.numberTimersEnabled, 'EnableCounter0' : self.counter0Enabled, 'EnableCounter1' : self.counter1Enabled, 'TimerCounterPinOffset' : self.timerCounterPinOffset } | |
configIO.section = 2 | |
def configTimerClock(self, TimerClockBase = None, TimerClockDivisor = None): | |
""" | |
Name: U3.configTimerClock(TimerClockBase = None, TimerClockDivisor = None) | |
Args: TimeClockBase, the base for the timer clock. | |
TimerClockDivisor, the divisor for the clock. | |
Desc: Writes and reads the time clock configuration. See section 5.2.4 | |
of the user's guide. | |
Note: TimerClockBase and TimerClockDivisor must be set at the same time. | |
""" | |
command = [ 0 ] * 10 | |
#command[0] = Checksum8 | |
command[1] = 0xF8 | |
command[2] = 0x02 | |
command[3] = 0x0A | |
#command[4] = Checksum16 (LSB) | |
#command[5] = Checksum16 (MSB) | |
#command[6] = Reserved | |
#command[7] = Reserved | |
if TimerClockBase is not None: | |
command[8] = ( 1 << 7 ) + ( TimerClockBase & 7 ) | |
if TimerClockDivisor is not None: | |
command[9] = TimerClockDivisor | |
elif TimerClockDivisor is not None: | |
raise LabJackException("You can't set just the divisor, must set both.") | |
result = self._writeRead(command, 10, [0xf8, 0x02, 0x0A]) | |
self.timerClockBase = ( result[8] & 7 ) | |
self.timerClockDivisor = result[9] | |
return { 'TimerClockBase' : self.timerClockBase, 'TimerClockDivisor' : self.timerClockDivisor } | |
configTimerClock.section = 2 | |
def toggleLED(self): | |
""" | |
Name: U3.toggleLED() | |
Args: None | |
Desc: Toggles the state LED on and off. | |
Example: | |
>>> import u3 | |
>>> d = u3.U3() | |
>>> d.toggleLED() | |
""" | |
self.getFeedback( LED( not self.ledState ) ) | |
self.ledState = not self.ledState | |
toggleLED.section = 3 | |
def setFIOState(self, fioNum, state = 1): | |
""" | |
Name: U3.setFIOState(fioNum, state = 1) | |
Args: fioNum, which FIO to change | |
state, 1 = High, 0 = Low | |
Desc: A convenience function to set the state of an FIO. Will also | |
set the direction to output. | |
Example: | |
>>> import u3 | |
>>> d = u3.U3() | |
>>> d.setFIOState(4, state = 1) | |
""" | |
self.getFeedback(BitDirWrite(fioNum, 1), BitStateWrite(fioNum, state)) | |
setFIOState.section = 3 | |
def getFIOState(self, fioNum): | |
""" | |
Name: U3.getFIOState(fioNum) | |
Args: fioNum, which FIO to read | |
Desc: A convenience function to read the state of an FIO. | |
Example: | |
>>> import u3 | |
>>> d = u3.U3() | |
>>> print d.getFIOState(4) | |
1 | |
""" | |
return self.getFeedback(BitStateRead(fioNum))[0] | |
getFIOState.section = 3 | |
def getTemperature(self): | |
""" | |
Name: U3.getTemperature() | |
Args: None | |
Desc: Reads the internal temperature sensor on the U3. Returns the | |
temperature in Kelvin. | |
""" | |
# Get the calibration data first, otherwise the conversion is way off (10 degC on my U3) | |
if self.calData is None: | |
self.getCalibrationData() | |
bits, = self.getFeedback( AIN(30, 31) ) | |
return self.binaryToCalibratedAnalogTemperature(bits) | |
def getAIN(self, posChannel, negChannel = 31, longSettle=False, quickSample=False): | |
""" | |
Name: U3.getAIN(posChannel, negChannel = 31, longSettle=False, | |
quickSample=False) | |
Args: posChannel, the positive channel to read from. | |
negChannel, the negitive channel to read from. | |
longSettle, set to True for longSettle | |
quickSample, set to True for quickSample | |
Desc: A convenience function to read an AIN. | |
Example: | |
>>> import u3 | |
>>> d = u3.U3() | |
>>> print d.getAIN( 0 ) | |
0.0501680038869 | |
""" | |
isSpecial = False | |
if negChannel == 32: | |
isSpecial = True | |
negChannel = 30 | |
bits = self.getFeedback(AIN(posChannel, negChannel, longSettle, quickSample))[0] | |
singleEnded = True | |
if negChannel != 31: | |
singleEnded = False | |
lvChannel = True | |
try: | |
if self.deviceName.endswith("-HV") and posChannel < 4: | |
lvChannel = False | |
except AttributeError: | |
pass | |
if isSpecial: | |
negChannel = 32 | |
return self.binaryToCalibratedAnalogVoltage(bits, isLowVoltage = lvChannel, isSingleEnded = singleEnded, isSpecialSetting = isSpecial, channelNumber = posChannel) | |
getAIN.section = 3 | |
def configAnalog(self, *args): | |
""" | |
Convenience method to configIO() that adds the given input numbers | |
in the range FIO0-EIO7 (0-15) to the analog team. That is, it adds | |
the given bit positions to those already set in the FIOAnalog | |
and EIOAnalog bitfields. | |
>>> import u3 | |
>>> d = u3.U3() | |
>>> d.debug = True | |
>>> d.configIO() | |
Sent: [0x47, 0xf8, 0x3, 0xb, 0x40, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0] | |
Result: [0x56, 0xf8, 0x3, 0xb, 0x4f, 0x0, 0x0, 0x0, 0x40, 0x0, 0xf, 0x0] | |
{'NumberOfTimersEnabled': 0, 'TimerCounterPinOffset': 4, 'DAC1Enable': 0, 'FIOAnalog': 15, 'EIOAnalog': 0, 'TimerCounterConfig': 64, 'EnableCounter1': False, 'EnableCounter0': False} | |
>>> d.configAnalog(u3.FIO4, u3.FIO5) | |
Sent: [0x47, 0xf8, 0x3, 0xb, 0x40, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0] | |
Result: [0x56, 0xf8, 0x3, 0xb, 0x4f, 0x0, 0x0, 0x0, 0x40, 0x0, 0xf, 0x0] | |
Sent: [0x93, 0xf8, 0x3, 0xb, 0x8c, 0x0, 0xd, 0x0, 0x40, 0x0, 0x3f, 0x0] | |
Result: [0x86, 0xf8, 0x3, 0xb, 0x7f, 0x0, 0x0, 0x0, 0x40, 0x0, 0x3f, 0x0] | |
{'NumberOfTimersEnabled': 0, 'TimerCounterPinOffset': 4, 'DAC1Enable': 0, 'FIOAnalog': 63, 'EIOAnalog': 0, 'TimerCounterConfig': 64, 'EnableCounter1': False, 'EnableCounter0': False} | |
""" | |
configIODict = self.configIO() | |
# Without args, return the same as configIO() | |
if len(args) == 0: | |
return configIODict | |
FIOAnalog, EIOAnalog = configIODict['FIOAnalog'], configIODict['EIOAnalog'] | |
# | |
for i in args: | |
if i > EIO7: | |
pass # Invalid. Must be in the range FIO0-EIO7. | |
elif i < EIO0: | |
FIOAnalog |= 2**i | |
else: | |
EIOAnalog |= 2**(i-EIO0) # Start the EIO counting at 0, not 8 | |
return self.configIO(FIOAnalog = FIOAnalog, EIOAnalog = EIOAnalog) | |
def configDigital(self, *args): | |
""" | |
The converse of configAnalog(). The convenience method to configIO, | |
adds the given input numbers in the range FIO0-EIO7 (0-15) to the | |
digital team. That is, it removes the given bit positions from those | |
already set in the FIOAnalog and EIOAnalog bitfields. | |
>>> import u3 | |
>>> d = u3.U3() | |
>>> d.debug = True | |
>>> d.configIO() | |
Sent: [0x47, 0xf8, 0x3, 0xb, 0x40, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0] | |
Result: [0x56, 0xf8, 0x3, 0xb, 0x4f, 0x0, 0x0, 0x0, 0x40, 0x0, 0xf, 0x0] | |
{'NumberOfTimersEnabled': 0, 'TimerCounterPinOffset': 4, 'DAC1Enable': 0, 'FIOAnalog': 15, 'EIOAnalog': 0, 'TimerCounterConfig': 64, 'EnableCounter1': False, 'EnableCounter0': False} | |
>>> d.configAnalog(u3.FIO4, u3.FIO5, u3.EIO0) | |
Sent: [0x47, 0xf8, 0x3, 0xb, 0x40, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0] | |
Result: [0x56, 0xf8, 0x3, 0xb, 0x4f, 0x0, 0x0, 0x0, 0x40, 0x0, 0xf, 0x0] | |
Sent: [0x94, 0xf8, 0x3, 0xb, 0x8d, 0x0, 0xd, 0x0, 0x40, 0x0, 0x3f, 0x1] | |
Result: [0x87, 0xf8, 0x3, 0xb, 0x80, 0x0, 0x0, 0x0, 0x40, 0x0, 0x3f, 0x1] | |
{'NumberOfTimersEnabled': 0, 'TimerCounterPinOffset': 4, 'DAC1Enable': 0, 'FIOAnalog': 63, 'EIOAnalog': 1, 'TimerCounterConfig': 64, 'EnableCounter1': False, 'EnableCounter0': False} | |
>>> d.configDigital(u3.FIO4, u3.FIO5, u3.EIO0) | |
Sent: [0x47, 0xf8, 0x3, 0xb, 0x40, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0] | |
Result: [0x87, 0xf8, 0x3, 0xb, 0x80, 0x0, 0x0, 0x0, 0x40, 0x0, 0x3f, 0x1] | |
Sent: [0x63, 0xf8, 0x3, 0xb, 0x5c, 0x0, 0xd, 0x0, 0x40, 0x0, 0xf, 0x0] | |
Result: [0x56, 0xf8, 0x3, 0xb, 0x4f, 0x0, 0x0, 0x0, 0x40, 0x0, 0xf, 0x0] | |
{'NumberOfTimersEnabled': 0, 'TimerCounterPinOffset': 4, 'DAC1Enable': 0, 'FIOAnalog': 15, 'EIOAnalog': 0, 'TimerCounterConfig': 64, 'EnableCounter1': False, 'EnableCounter0': False} | |
""" | |
configIODict = self.configIO() | |
# Without args, return the same as configIO() | |
if len(args) == 0: | |
return configIODict | |
FIOAnalog, EIOAnalog = configIODict['FIOAnalog'], configIODict['EIOAnalog'] | |
# | |
for i in args: | |
if i > EIO7: | |
pass # Invalid. Must be in the range FIO0-EIO7. | |
elif i < EIO0: | |
if FIOAnalog & 2**i: # If it is set | |
FIOAnalog ^= 2**i # Remove it | |
else: | |
if EIOAnalog & 2**(i-EIO0): # Start the EIO counting at 0, not 8 | |
EIOAnalog ^= 2**(i-EIO0) | |
return self.configIO(FIOAnalog = FIOAnalog, EIOAnalog = EIOAnalog) | |
def _buildBuffer(self, sendBuffer, readLen, commandlist): | |
""" | |
Builds up the buffer to be written for getFeedback | |
""" | |
for cmd in commandlist: | |
if isinstance(cmd, FeedbackCommand): | |
sendBuffer += cmd.cmdBytes | |
readLen += cmd.readLen | |
elif isinstance(cmd, list): | |
sendBuffer, readLen = self._buildBuffer(sendBuffer, readLen, cmd) | |
return (sendBuffer, readLen) | |
_buildBuffer.section = 4 | |
def _buildFeedbackResults(self, rcvBuffer, commandlist, results, i): | |
""" | |
Builds the result list from the results of getFeedback | |
""" | |
for cmd in commandlist: | |
if isinstance(cmd, FeedbackCommand): | |
results.append(cmd.handle(rcvBuffer[i:i+cmd.readLen])) | |
i += cmd.readLen | |
elif isinstance(cmd, list): | |
self._buildFeedbackResults(rcvBuffer, cmd, results, i) | |
return results | |
_buildFeedbackResults.section = 4 | |
def getFeedback(self, *commandlist): | |
""" | |
Name: U3.getFeedback(commandlist) | |
Args: the FeedbackCommands to run | |
Desc: Forms the commandlist into a packet, sends it to the U3, and reads the response. | |
Examples: | |
>>> myU3 = u3.U3() | |
>>> ledCommand = u3.LED(False) | |
>>> ain0Command = u3.AIN(0, 31, True) | |
>>> myU3.getFeedback(ledCommand, ain0Command) | |
[None, 9376] | |
OR if you like the list version better: | |
>>> myU3 = U3() | |
>>> ledCommand = u3.LED(False) | |
>>> ain0Command = u3.AIN(30, 31, True) | |
>>> commandList = [ ledCommand, ain0Command ] | |
>>> myU3.getFeedback(commandList) | |
[None, 9376] | |
""" | |
sendBuffer = [0] * 7 | |
sendBuffer[1] = 0xF8 | |
readLen = 9 | |
sendBuffer, readLen = self._buildBuffer(sendBuffer, readLen, commandlist) | |
if len(sendBuffer) % 2: | |
sendBuffer += [0] | |
sendBuffer[2] = len(sendBuffer) / 2 - 3 | |
if readLen % 2: | |
readLen += 1 | |
if len(sendBuffer) > MAX_USB_PACKET_LENGTH: | |
raise LabJackException("ERROR: The feedback command you are attempting to send is bigger than 64 bytes ( %s bytes ). Break your commands up into separate calls to getFeedback()." % len(sendBuffer)) | |
if readLen > MAX_USB_PACKET_LENGTH: | |
raise LabJackException("ERROR: The feedback command you are attempting to send would yield a response that is greater than 64 bytes ( %s bytes ). Break your commands up into separate calls to getFeedback()." % readLen) | |
rcvBuffer = self._writeRead(sendBuffer, readLen, [], checkBytes = False, stream = False, checksum = True) | |
# Check the response for errors | |
try: | |
self._checkCommandBytes(rcvBuffer, [0xF8]) | |
if rcvBuffer[3] != 0x00: | |
raise LabJackException("Got incorrect command bytes") | |
except LowlevelErrorException, e: | |
if isinstance(commandlist[0], list): | |
culprit = commandlist[0][ (rcvBuffer[7] -1) ] | |
else: | |
culprit = commandlist[ (rcvBuffer[7] -1) ] | |
raise LowlevelErrorException("\nThis Command\n %s\nreturned an error:\n %s" % (culprit , lowlevelErrorToString(rcvBuffer[6]))) | |
results = [] | |
i = 9 | |
return self._buildFeedbackResults(rcvBuffer, commandlist, results, i) | |
getFeedback.section = 2 | |
def readMem(self, blockNum, readCal=False): | |
""" | |
Name: U3.readMem(blockNum, readCal=False) | |
Args: blockNum, which block to read from | |
readCal, set to True to read from calibration instead. | |
Desc: Reads 1 block (32 bytes) from the non-volatile user or | |
calibration memory. Please read section 5.2.6 of the user's guide | |
before you do something you may regret. | |
NOTE: Do not call this function while streaming. | |
""" | |
command = [ 0 ] * 8 | |
#command[0] = Checksum8 | |
command[1] = 0xF8 | |
command[2] = 0x01 | |
command[3] = 0x2A | |
if readCal: | |
command[3] = 0x2D | |
#command[4] = Checksum16 (LSB) | |
#command[5] = Checksum16 (MSB) | |
command[6] = 0x00 | |
command[7] = blockNum | |
result = self._writeRead(command, 40, [0xF8, 0x11, command[3]]) | |
return result[8:] | |
readMem.section = 2 | |
def readCal(self, blockNum): | |
""" | |
Name: U3.readCal(blockNum) | |
Args: blockNum, which block to read | |
Desc: See the description of readMem and section 5.2.6 of the user's | |
guide. | |
Note: Do not call this function while streaming. | |
""" | |
return self.readMem(blockNum, readCal = True) | |
readCal.section = 2 | |
def writeMem(self, blockNum, data, writeCal=False): | |
""" | |
Name: U3.writeMem(blockNum, data, writeCal=False) | |
Args: blockNum, which block to write | |
data, a list of bytes to write. | |
writeCal, set to True to write to calibration instead | |
Desc: Writes 1 block (32 bytes) from the non-volatile user or | |
calibration memory. Please read section 5.2.7 of the user's guide | |
before you do something you may regret. Memory must be erased | |
before writing. | |
Note: Do not call this function while streaming. | |
""" | |
if not isinstance(data, list): | |
raise LabJackException("Data must be a list of bytes") | |
command = [ 0 ] * 40 | |
#command[0] = Checksum8 | |
command[1] = 0xF8 | |
command[2] = 0x11 | |
command[3] = 0x28 | |
if writeCal: | |
command[3] = 0x2B | |
#command[4] = Checksum16 (LSB) | |
#command[5] = Checksum16 (MSB) | |
command[6] = 0x00 | |
command[7] = blockNum | |
command[8:] = data | |
self._writeRead(command, 8, [0xF8, 0x01, command[3]]) | |
writeMem.section = 2 | |
def writeCal(self, blockNum): | |
""" | |
Name: U3.writeCal(blockNum, data) | |
Args: blockNum, which block to write | |
data, a list of bytes | |
Desc: See the description of writeMem and section 5.2.7 of the user's | |
guide. | |
Note: Do not call this function while streaming. | |
""" | |
return self.writeMem(blockNum, data, writeCal = True) | |
writeCal.section = 2 | |
def eraseMem(self, eraseCal=False): | |
""" | |
Name: U3.eraseMem(eraseCal=False) | |
Args: eraseCal, set to True to erase the calibration memory instead | |
Desc: The U3 uses flash memory that must be erased before writing. | |
Please read section 5.2.8 of the user's guide before you do | |
something you may regret. | |
Note: Do not call this function while streaming. | |
""" | |
if eraseCal: | |
command = [ 0 ] * 8 | |
#command[0] = Checksum8 | |
command[1] = 0xF8 | |
command[2] = 0x01 | |
command[3] = 0x2C | |
#command[4] = Checksum16 (LSB) | |
#command[5] = Checksum16 (MSB) | |
command[6] = 0x4C | |
command[7] = 0x6C | |
else: | |
command = [ 0 ] * 6 | |
#command[0] = Checksum8 | |
command[1] = 0xF8 | |
command[2] = 0x00 | |
command[3] = 0x29 | |
#command[4] = Checksum16 (LSB) | |
#command[5] = Checksum16 (MSB) | |
self._writeRead(command, 8, [0xF8, 0x01, command[3]]) | |
eraseMem.section = 2 | |
def eraseCal(self): | |
""" | |
Name: U3.eraseCal() | |
Args: None | |
Desc: See the description of writeMem and section 5.2.8 of the user's | |
guide. | |
Note: Do not call this function while streaming. | |
""" | |
return self.eraseMem(eraseCal = True) | |
eraseCal.section = 2 | |
def reset(self, hardReset = False): | |
""" | |
Name: U3.reset(hardReset = False) | |
Args: hardReset, set to True for a hard reset. | |
Desc: Causes a soft or hard reset. A soft reset consists of | |
re-initializing most variables without re-enumeration. A hard | |
reset is a reboot of the processor and does cause re-enumeration. | |
See section 5.2.9 of the User's guide. | |
""" | |
command = [ 0 ] * 4 | |
#command[0] = Checksum8 | |
command[1] = 0x99 | |
command[2] = 1 | |
if hardReset: | |
command[2] = 2 | |
command[3] = 0x00 | |
command = setChecksum8(command, 4) | |
self._writeRead(command, 4, [], False, False, False) | |
reset.section = 2 | |
def streamConfig(self, NumChannels = 1, SamplesPerPacket = 25, InternalStreamClockFrequency = 0, DivideClockBy256 = False, Resolution = 3, ScanInterval = 1, PChannels = [30], NChannels = [31], SampleFrequency = None): | |
""" | |
Name: U3.streamConfig(NumChannels = 1, SamplesPerPacket = 25, | |
InternalStreamClockFrequency = 0, | |
DivideClockBy256 = False, Resolution = 3, | |
ScanInterval = 1, PChannels = [30], | |
NChannels = [31], SampleFrequency = None) | |
Args: NumChannels, the number of channels to stream | |
Resolution, the resolution of the samples (0 - 3) | |
PChannels, a list of channel numbers to stream | |
NChannels, a list of channel options bytes | |
Set Either: | |
SampleFrequency, the frequency in Hz to sample | |
-- OR -- | |
SamplesPerPacket, how many samples make one packet | |
InternalStreamClockFrequency, 0 = 4 MHz, 1 = 48 MHz | |
DivideClockBy256, True = divide the clock by 256 | |
ScanInterval, clock/ScanInterval = frequency. | |
Desc: Stream mode operates on a table of channels that are scanned | |
at the specified scan rate. Before starting a stream, you need | |
to call this function to configure the table and scan clock. | |
Note: Requires U3 hardware version 1.21 or greater. | |
""" | |
if len(PChannels) != NumChannels: | |
raise LabJackException("Length of PChannels didn't match NumChannels") | |
if len(NChannels) != NumChannels: | |
raise LabJackException("Length of NChannels didn't match NumChannels") | |
if len(PChannels) != len(NChannels): | |
raise LabJackException("Length of PChannels didn't match the length of NChannels") | |
if SampleFrequency != None: | |
if SampleFrequency < 1000: | |
if SampleFrequency < 25: | |
SamplesPerPacket = SampleFrequency | |
DivideClockBy256 = True | |
ScanInterval = 15625/SampleFrequency | |
else: | |
DivideClockBy256 = False | |
ScanInterval = 4000000/SampleFrequency | |
# Force Scan Interval into correct range | |
ScanInterval = min( ScanInterval, 65535 ) | |
ScanInterval = int( ScanInterval ) | |
ScanInterval = max( ScanInterval, 1 ) | |
# Same with Samples per packet | |
SamplesPerPacket = max( SamplesPerPacket, 1) | |
SamplesPerPacket = int( SamplesPerPacket ) | |
SamplesPerPacket = min ( SamplesPerPacket, 25) | |
command = [ 0 ] * ( 12 + (NumChannels * 2) ) | |
#command[0] = Checksum8 | |
command[1] = 0xF8 | |
command[2] = NumChannels+3 | |
command[3] = 0x11 | |
#command[4] = Checksum16 (LSB) | |
#command[5] = Checksum16 (MSB) | |
command[6] = NumChannels | |
command[7] = SamplesPerPacket | |
#command[8] = Reserved | |
command[9] |= ( InternalStreamClockFrequency & 0x01 ) << 3 | |
if DivideClockBy256: | |
command[9] |= 1 << 2 | |
command[9] |= ( Resolution & 3 ) | |
t = struct.pack("<H", ScanInterval) | |
command[10] = ord(t[0]) | |
command[11] = ord(t[1]) | |
for i in range(NumChannels): | |
command[12+(i*2)] = PChannels[i] | |
command[13+(i*2)] = NChannels[i] | |
self._writeRead(command, 8, [0xF8, 0x01, 0x11]) | |
self.streamSamplesPerPacket = SamplesPerPacket | |
self.streamChannelNumbers = PChannels | |
self.streamNegChannels = NChannels | |
self.streamConfiged = True | |
if InternalStreamClockFrequency == 1: | |
freq = float(48000000) | |
else: | |
freq = float(4000000) | |
if DivideClockBy256: | |
freq /= 256 | |
freq = freq/ScanInterval | |
self.packetsPerRequest = max(1, int(freq/SamplesPerPacket)) | |
self.packetsPerRequest = min(self.packetsPerRequest, 48) | |
streamConfig.section = 2 | |
def processStreamData(self, result, numBytes = None): | |
""" | |
Name: U3.processStreamData(result, numBytes = None) | |
Args: result, the string returned from streamData() | |
numBytes, the number of bytes per packet. | |
Desc: Breaks stream data into individual channels and applies | |
calibrations. | |
>>> reading = d.streamData(convert = False) | |
>>> print proccessStreamData(reading['result']) | |
defaultDict(list, {'AIN0' : [3.123, 3.231, 3.232, ...]}) | |
""" | |
if numBytes is None: | |
numBytes = 14 + (self.streamSamplesPerPacket * 2) | |
returnDict = collections.defaultdict(list) | |
for packet in self.breakupPackets(result, numBytes): | |
for sample in self.samplesFromPacket(packet): | |
if self.streamPacketOffset >= len(self.streamChannelNumbers): | |
self.streamPacketOffset = 0 | |
if self.streamChannelNumbers[self.streamPacketOffset] in (193, 194): | |
value = struct.unpack('<BB', sample ) | |
elif self.streamChannelNumbers[self.streamPacketOffset] in (200, 201, 210, 211, 224): | |
value = struct.unpack('<H', sample )[0] | |
else: | |
if self.streamNegChannels[self.streamPacketOffset] != 31: | |
# do signed | |
value = struct.unpack('<H', sample )[0] | |
singleEnded = False | |
else: | |
# do unsigned | |
value = struct.unpack('<H', sample )[0] | |
singleEnded = True | |
lvChannel = True | |
if self.deviceName.lower().endswith('hv') and self.streamChannelNumbers[self.streamPacketOffset] < 4: | |
lvChannel = False | |
value = self.binaryToCalibratedAnalogVoltage(value, isLowVoltage = lvChannel, isSingleEnded = singleEnded, channelNumber = self.streamChannelNumbers[self.streamPacketOffset]) | |
returnDict["AIN%s" % self.streamChannelNumbers[self.streamPacketOffset]].append(value) | |
self.streamPacketOffset += 1 | |
return returnDict | |
processStreamData.section = 3 | |
def watchdog(self, ResetOnTimeout = False, SetDIOStateOnTimeout = False, TimeoutPeriod = 60, DIOState = 0, DIONumber = 0, onlyRead=False): | |
""" | |
Name: U3.watchdog(ResetOnTimeout = False, SetDIOStateOnTimeout = False, | |
TimeoutPeriod = 60, DIOState = 0, DIONumber = 0, | |
onlyRead = False) | |
Args: Check out section 5.2.14 of the user's guide. | |
Set onlyRead to True to perform only a read | |
Desc: This function will write the configuration of the watchdog, | |
unless onlyRead is set to True. | |
Returns a dictionary: | |
{ | |
'WatchDogEnabled' : True if the watchdog is enabled, otherwise False | |
'ResetOnTimeout' : If True, the device will reset on timeout. | |
'SetDIOStateOnTimeout' : If True, the state of a DIO will be set | |
'TimeoutPeriod' : Timeout Period in seconds | |
'DIOState' : The state the DIO will be set to on timeout | |
'DIONumber' : Which DIO will be set on timeout | |
} | |
NOTE: Requires U3 hardware version 1.21 or greater. | |
""" | |
command = [ 0 ] * 16 | |
#command[0] = Checksum8 | |
command[1] = 0xF8 | |
command[2] = 0x05 | |
command[3] = 0x09 | |
#command[4] = Checksum16 (LSB) | |
#command[5] = Checksum16 (MSB) | |
if not onlyRead: | |
command[6] = 1 | |
if ResetOnTimeout: | |
command[7] |= 1 << 5 | |
if SetDIOStateOnTimeout: | |
command[7] |= 1 << 4 | |
t = struct.pack("<H", TimeoutPeriod) | |
command[8] = ord(t[0]) | |
command[9] = ord(t[1]) | |
command[10] = (( DIOState & 1 ) << 7) + ( DIONumber & 15) | |
result = self._writeRead(command, 16, [0xF8, 0x05, 0x09]) | |
watchdogStatus = {} | |
if result[7] == 0 or result[7] == 255: | |
watchdogStatus['WatchDogEnabled'] = False | |
watchdogStatus['ResetOnTimeout'] = False | |
watchdogStatus['SetDIOStateOnTimeout'] = False | |
else: | |
watchdogStatus['WatchDogEnabled'] = True | |
if (( result[7] >> 5 ) & 1): | |
watchdogStatus['ResetOnTimeout'] = True | |
else: | |
watchdogStatus['ResetOnTimeout'] = False | |
if (( result[7] >> 4 ) & 1): | |
watchdogStatus['SetDIOStateOnTimeout'] = True | |
else: | |
watchdogStatus['SetDIOStateOnTimeout'] = False | |
watchdogStatus['TimeoutPeriod'] = struct.unpack('<H', struct.pack("BB", *result[8:10])) | |
if (( result[10] >> 7 ) & 1): | |
watchdogStatus['DIOState'] = 1 | |
else: | |
watchdogStatus['DIOState'] = 0 | |
watchdogStatus['DIONumber'] = ( result[10] & 15 ) | |
return watchdogStatus | |
watchdog.section = 2 | |
SPIModes = { 'A' : 0, 'B' : 1, 'C' : 2, 'D' : 3 } | |
def spi(self, SPIBytes, AutoCS=True, DisableDirConfig = False, SPIMode = 'A', SPIClockFactor = 0, CSPINNum = 4, CLKPinNum = 5, MISOPinNum = 6, MOSIPinNum = 7): | |
""" | |
Name: U3.spi(SPIBytes, AutoCS=True, DisableDirConfig = False, | |
SPIMode = 'A', SPIClockFactor = 0, CSPINNum = 4, | |
CLKPinNum = 5, MISOPinNum = 6, MOSIPinNum = 7) | |
Args: SPIBytes, a list of bytes to be transferred. | |
See Section 5.2.15 of the user's guide. | |
Desc: Sends and receives serial data using SPI synchronous | |
communication. | |
NOTE: Requires U3 hardware version 1.21 or greater. | |
""" | |
if not isinstance(SPIBytes, list): | |
raise LabJackException("SPIBytes MUST be a list of bytes") | |
numSPIBytes = len(SPIBytes) | |
oddPacket = False | |
if numSPIBytes%2 != 0: | |
SPIBytes.append(0) | |
numSPIBytes = numSPIBytes + 1 | |
oddPacket = True | |
command = [ 0 ] * (13 + numSPIBytes) | |
#command[0] = Checksum8 | |
command[1] = 0xF8 | |
command[2] = 4 + (numSPIBytes/2) | |
command[3] = 0x3A | |
#command[4] = Checksum16 (LSB) | |
#command[5] = Checksum16 (MSB) | |
if AutoCS: | |
command[6] |= (1 << 7) | |
if DisableDirConfig: | |
command[6] |= (1 << 6) | |
command[6] |= ( self.SPIModes[SPIMode] & 3 ) | |
command[7] = SPIClockFactor | |
#command[8] = Reserved | |
command[9] = CSPINNum | |
command[10] = CLKPinNum | |
command[11] = MISOPinNum | |
command[12] = MOSIPinNum | |
command[13] = numSPIBytes | |
if oddPacket: | |
command[13] = numSPIBytes - 1 | |
command[14:] = SPIBytes | |
result = self._writeRead(command, 8+numSPIBytes, [ 0xF8, 1+(numSPIBytes/2), 0x3A ]) | |
return result[8:] | |
spi.section = 2 | |
def asynchConfig(self, Update = True, UARTEnable = True, DesiredBaud = 9600, olderHardware = False, configurePins = True ): | |
""" | |
Name: U3.asynchConfig(Update = True, UARTEnable = True, | |
DesiredBaud = 9600, olderHardware = False, | |
configurePins = True) | |
Args: See section 5.2.16 of the User's Guide. | |
olderHardware, If using hardware 1.21, please set olderHardware | |
to True and read the timer configuration first. | |
configurePins, Will call the configIO to set up pins for you. | |
Desc: Configures the U3 UART for asynchronous communication. | |
returns a dictionary: | |
{ | |
'Update' : True means new parameters were written | |
'UARTEnable' : True means the UART is enabled | |
'BaudFactor' : The baud factor being used | |
} | |
Note: Requires U3 hardware version 1.21+. | |
""" | |
if configurePins: | |
self.configIO(EnableUART=True) | |
command = [ 0 ] * 10 | |
#command[0] = Checksum8 | |
command[1] = 0xF8 | |
command[2] = 0x02 | |
command[3] = 0x14 | |
#command[4] = Checksum16 (LSB) | |
#command[5] = Checksum16 (MSB) | |
#command[6] = 0x00 | |
if Update: | |
command[7] |= ( 1 << 7 ) | |
if UARTEnable: | |
command[7] |= ( 1 << 6 ) | |
#command[8] = Reserved | |
if olderHardware: | |
command[9] = (2**8) - self.timerClockBase/DesiredBaud | |
else: | |
BaudFactor = (2**16) - 48000000/(2 * DesiredBaud) | |
t = struct.pack("<H", BaudFactor) | |
command[8] = ord(t[0]) | |
command[9] = ord(t[1]) | |
if olderHardware: | |
result = self._writeRead(command, 10, [0xF8, 0x02, 0x14]) | |
else: | |
result = self._writeRead(command, 10, [0xF8, 0x02, 0x14]) | |
returnDict = {} | |
if ( ( result[7] >> 7 ) & 1 ): | |
returnDict['Update'] = True | |
else: | |
returnDict['Update'] = False | |
if ( ( result[7] >> 6 ) & 1): | |
returnDict['UARTEnable'] = True | |
else: | |
returnDict['UARTEnable'] = False | |
if olderHardware: | |
returnDict['BaudFactor'] = result[9] | |
else: | |
returnDict['BaudFactor'] = struct.unpack("<H", struct.pack("BB", *result[8:]))[0] | |
return returnDict | |
asynchConfig.section = 2 | |
def asynchTX(self, AsynchBytes): | |
""" | |
Name: U3.asynchTX(AsynchBytes) | |
Args: AsynchBytes, must be a list of bytes to transfer. | |
Desc: Sends bytes to the U3 UART which will be sent asynchronously on | |
the transmit line. See section 5.2.17 of the user's guide. | |
returns a dictionary: | |
{ | |
'NumAsynchBytesSent' : Number of Asynch Bytes Sent | |
'NumAsynchBytesInRXBuffer' : How many bytes are currently in the | |
RX buffer. | |
} | |
Note: Requres U3 hardware version 1.21 or greater. | |
""" | |
if not isinstance(AsynchBytes, list): | |
raise LabJackException("AsynchBytes must be a list") | |
numBytes = len(AsynchBytes) | |
oddPacket = False | |
if numBytes%2 != 0: | |
AsynchBytes.append(0) | |
numBytes = numBytes+1 | |
oddPacket = True | |
command = [ 0 ] * ( 8 + numBytes) | |
#command[0] = Checksum8 | |
command[1] = 0xF8 | |
command[2] = 1 + ( numBytes/2 ) | |
command[3] = 0x15 | |
#command[4] = Checksum16 (LSB) | |
#command[5] = Checksum16 (MSB) | |
#command[6] = 0x00 | |
command[7] = numBytes | |
if oddPacket: | |
command[7] = numBytes - 1 | |
command[8:] = AsynchBytes | |
result = self._writeRead(command, 10, [0xF8, 0x02, 0x15]) | |
return { 'NumAsynchBytesSent' : result[7], 'NumAsynchBytesInRXBuffer' : result[8] } | |
asynchTX.section = 2 | |
def asynchRX(self, Flush = False): | |
""" | |
Name: U3.asynchRX(Flush = False) | |
Args: Flush, Set to True to flush | |
Desc: Reads the oldest 32 bytes from the U3 UART RX buffer | |
(received on receive terminal). The buffer holds 256 bytes. See | |
section 5.2.18 of the User's Guide. | |
returns a dictonary: | |
{ | |
'AsynchBytes' : List of received bytes | |
'NumAsynchBytesInRXBuffer' : Number of AsynchBytes are in the RX | |
Buffer. | |
} | |
Note: Requres U3 hardware version 1.21 or greater. | |
""" | |
command = [ 0 ] * 8 | |
#command[0] = Checksum8 | |
command[1] = 0xF8 | |
command[2] = 0x01 | |
command[3] = 0x16 | |
#command[4] = Checksum16 (LSB) | |
#command[5] = Checksum16 (MSB) | |
#command[6] = 0x00 | |
if Flush: | |
command[7] = 1 | |
result = self._writeRead(command, 40, [0xF8, 0x11, 0x16]) | |
return { 'AsynchBytes' : result[8:], 'NumAsynchBytesInRXBuffer' : result[7] } | |
asynchRX.section = 2 | |
def i2c(self, Address, I2CBytes, ResetAtStart = False, EnableClockStretching = False, SpeedAdjust = 0, SDAPinNum = 6, SCLPinNum = 7, NumI2CBytesToReceive = 0, AddressByte = None): | |
""" | |
Name: U3.i2c(Address, I2CBytes, ResetAtStart = False, | |
EnableClockStretching = False, SpeedAdjust = 0, | |
SDAPinNum = 6, SCLPinNum = 7, NumI2CBytesToReceive = 0, | |
AddressByte = None) | |
Args: Address, the address (not shifted over) | |
I2CBytes, must be a list of bytes to send. | |
See section 5.2.19 of the user's guide. | |
AddressByte, use this if you don't want a shift applied. | |
This address will be put it in the low-level | |
packet directly and overrides Address. Optional. | |
Desc: Sends and receives serial data using I2C synchronous | |
communication. | |
Note: Requires hardware version 1.21 or greater. | |
""" | |
if not isinstance(I2CBytes, list): | |
raise LabJackException("I2CBytes must be a list") | |
numBytes = len(I2CBytes) | |
oddPacket = False | |
if numBytes%2 != 0: | |
I2CBytes.append(0) | |
numBytes = numBytes + 1 | |
oddPacket = True | |
command = [ 0 ] * (14 + numBytes) | |
#command[0] = Checksum8 | |
command[1] = 0xF8 | |
command[2] = 4 + (numBytes/2) | |
command[3] = 0x3B | |
#command[4] = Checksum16 (LSB) | |
#command[5] = Checksum16 (MSB) | |
if ResetAtStart: | |
command[6] |= (1 << 1) | |
if EnableClockStretching: | |
command[6] |= (1 << 3) | |
command[7] = SpeedAdjust | |
command[8] = SDAPinNum | |
command[9] = SCLPinNum | |
if AddressByte != None: | |
command[10] = AddressByte | |
else: | |
command[10] = Address << 1 | |
command[12] = numBytes | |
if oddPacket: | |
command[12] = numBytes-1 | |
command[13] = NumI2CBytesToReceive | |
command[14:] = I2CBytes | |
oddResponse = False | |
if NumI2CBytesToReceive%2 != 0: | |
NumI2CBytesToReceive = NumI2CBytesToReceive+1 | |
oddResponse = True | |
result = self._writeRead(command, 12+NumI2CBytesToReceive, [0xF8, (3+(NumI2CBytesToReceive/2)), 0x3B]) | |
if len(result) > 12: | |
if oddResponse: | |
return { 'AckArray' : result[8:12], 'I2CBytes' : result[12:-1] } | |
else: | |
return { 'AckArray' : result[8:12], 'I2CBytes' : result[12:] } | |
else: | |
return { 'AckArray' : result[8:], 'I2CBytes' : [] } | |
i2c.section = 2 | |
def sht1x(self, DataPinNum = 4, ClockPinNum = 5, SHTOptions = 0xc0): | |
""" | |
Name: U3.sht1x(DataPinNum = 4, ClockPinNum = 5, SHTOptions = 0xc0) | |
Args: See section 5.2.20 of the user's guide. | |
SHTOptions, see below. | |
Desc: Reads temperature and humidity from a Sensirion SHT1X sensor | |
(which is used by the EI-1050). | |
Returns a dictonary: | |
{ | |
'StatusReg' : SHT1X status register | |
'StatusRegCRC' : SHT1X status register CRC value | |
'Temperature' : The temperature in C | |
'TemperatureCRC' : The CRC value for the temperature | |
'Humidity' : The humidity | |
'HumidityCRC' : The CRC value for the humidity | |
} | |
Note: Requires hardware version 1.21 or greater. | |
SHTOptions (and proof people read documentation): | |
bit 7 = Read Temperature | |
bit 6 = Read Realtive Humidity | |
bit 2 = Heater. 1 = on, 0 = off | |
bit 1 = Reserved at 0 | |
bit 0 = Resolution. 1 = 8 bit RH, 12 bit T; 0 = 12 RH, 14 bit T | |
""" | |
command = [ 0 ] * 10 | |
#command[0] = Checksum8 | |
command[1] = 0xF8 | |
command[2] = 0x02 | |
command[3] = 0x39 | |
#command[4] = Checksum16 (LSB) | |
#command[5] = Checksum16 (MSB) | |
command[6] = DataPinNum | |
command[7] = ClockPinNum | |
#command[8] = Reserved | |
command[9] = SHTOptions | |
result = self._writeRead(command, 16, [0xF8, 0x05, 0x39]) | |
val = (result[11]*256) + result[10] | |
temp = -39.60 + 0.01*val | |
val = (result[14]*256) + result[13] | |
humid = -4 + 0.0405*val + -.0000028*(val*val) | |
humid = (temp - 25)*(0.01 + 0.00008*val) + humid | |
return { 'StatusReg' : result[8], 'StatusRegCRC' : result[9], 'Temperature' : temp, 'TemperatureCRC' : result[12] , 'Humidity' : humid, 'HumidityCRC' : result[15] } | |
sht1x.section = 2 | |
def binaryToCalibratedAnalogVoltage(self, bits, isLowVoltage = True, isSingleEnded = True, isSpecialSetting = False, channelNumber = 0): | |
""" | |
Name: U3.binaryToCalibratedAnalogVoltage(bits, isLowVoltage = True, | |
isSingleEnded = True, | |
isSpecialSetting = False, | |
channelNumber = 0) | |
Args: bits, the binary value of the reading. | |
isLowVoltage, True if the reading came from a low-voltage channel | |
isSingleEnded, True if the reading is not differential | |
isSpecialSetting, True if the reading came from special range | |
channelNumber, used to apply the correct calibration for HV | |
Desc: Converts the bits returned from AIN functions into a calibrated | |
voltage. | |
Example: | |
>>> import u3 | |
>>> d = u3.U3() | |
>>> bits = d.getFeedback( u3.AIN(0, 31))[0] | |
>>> print bits | |
1248 | |
>>> print d.binaryToCalibratedAnalogVoltage(bits) | |
0.046464288000000006 | |
""" | |
hasCal = self.calData is not None | |
if isLowVoltage: | |
if isSingleEnded and not isSpecialSetting: | |
if hasCal: | |
return ( bits * self.calData['lvSESlope'] ) + self.calData['lvSEOffset'] | |
else: | |
return ( bits * 0.000037231 ) + 0 | |
elif isSpecialSetting: | |
if hasCal: | |
return ( bits * self.calData['lvDiffSlope'] ) + self.calData['lvDiffOffset'] + self.calData['vRefAtCAl'] | |
else: | |
return (bits * 0.000074463) | |
else: | |
if hasCal: | |
return ( bits * self.calData['lvDiffSlope'] ) + self.calData['lvDiffOffset'] | |
else: | |
return (bits * 0.000074463) - 2.44 | |
else: | |
if isSingleEnded and not isSpecialSetting: | |
if hasCal: | |
return ( bits * self.calData['hvAIN%sSlope' % channelNumber] ) + self.calData['hvAIN%sOffset' % channelNumber] | |
else: | |
return ( bits * 0.000314 ) + -10.3 | |
elif isSpecialSetting: | |
if hasCal: | |
hvSlope = self.calData['hvAIN%sSlope' % channelNumber] | |
hvOffset = self.calData['hvAIN%sOffset' % channelNumber] | |
diffR = ( bits * self.calData['lvDiffSlope'] ) + self.calData['lvDiffOffset'] + self.calData['vRefAtCAl'] | |
reading = diffR * hvSlope / self.calData['lvSESlope'] + hvOffset | |
return reading | |
else: | |
return (bits * 0.000074463) * (0.000314 / 0.000037231) + -10.3 | |
else: | |
raise Exception, "Can't do differential on high voltage channels" | |
binaryToCalibratedAnalogVoltage.section = 3 | |
def binaryToCalibratedAnalogTemperature(self, bytesTemperature): | |
hasCal = self.calData is not None | |
if hasCal: | |
return self.calData['tempSlope'] * float(bytesTemperature) | |
else: | |
return float(bytesTemperature) * 0.013021 | |
def voltageToDACBits(self, volts, dacNumber = 0, is16Bits = False): | |
""" | |
Name: U3.voltageToDACBits(volts, dacNumber = 0, is16Bits = False) | |
Args: volts, the voltage you would like to set the DAC to. | |
dacNumber, 0 or 1, helps apply the correct calibration | |
is16Bits, True if you are going to use the 16-bit DAC command | |
Desc: Takes a voltage, and turns it into the bits needed for the DAC | |
Feedback commands. | |
""" | |
if self.calData is not None: | |
if is16Bits: | |
bits = ( volts * self.calData['dac%sSlope' % dacNumber] * 256) + self.calData['dac%sOffset' % dacNumber] * 256 | |
else: | |
bits = ( volts * self.calData['dac%sSlope' % dacNumber] ) + self.calData['dac%sOffset' % dacNumber] | |
else: | |
bits = ( volts / 4.95 ) * 256 | |
return int(bits) | |
voltageToDACBits.section = 3 | |
def getCalibrationData(self): | |
""" | |
Name: U3.getCalibrationData() | |
Args: None | |
Desc: Reads in the U3's calibrations, so they can be applied to | |
readings. Section 2.6.2 of the User's Guide is helpful. Sets up | |
an internal calData dict for any future calls that need | |
calibration. | |
""" | |
self.calData = dict() | |
calData = self.readCal(0) | |
self.calData['lvSESlope'] = toDouble(calData[0:8]) | |
self.calData['lvSEOffset'] = toDouble(calData[8:16]) | |
self.calData['lvDiffSlope'] = toDouble(calData[16:24]) | |
self.calData['lvDiffOffset'] = toDouble(calData[24:32]) | |
calData = self.readCal(1) | |
self.calData['dac0Slope'] = toDouble(calData[0:8]) | |
self.calData['dac0Offset'] = toDouble(calData[8:16]) | |
self.calData['dac1Slope'] = toDouble(calData[16:24]) | |
self.calData['dac1Offset'] = toDouble(calData[24:32]) | |
calData = self.readCal(2) | |
self.calData['tempSlope'] = toDouble(calData[0:8]) | |
self.calData['vRefAtCAl'] = toDouble(calData[8:16]) | |
self.calData['vRef1.5AtCal'] = toDouble(calData[16:24]) | |
self.calData['vRegAtCal'] = toDouble(calData[24:32]) | |
try: | |
#these blocks do not exist on hardware revisions < 1.30 | |
calData = self.readCal(3) | |
self.calData['hvAIN0Slope'] = toDouble(calData[0:8]) | |
self.calData['hvAIN1Slope'] = toDouble(calData[8:16]) | |
self.calData['hvAIN2Slope'] = toDouble(calData[16:24]) | |
self.calData['hvAIN3Slope'] = toDouble(calData[24:32]) | |
calData = self.readCal(4) | |
self.calData['hvAIN0Offset'] = toDouble(calData[0:8]) | |
self.calData['hvAIN1Offset'] = toDouble(calData[8:16]) | |
self.calData['hvAIN2Offset'] = toDouble(calData[16:24]) | |
self.calData['hvAIN3Offset'] = toDouble(calData[24:32]) | |
except LowlevelErrorException, ex: | |
if ex.errorCode != 26: | |
#not an invalid block error, so do not disregard | |
raise ex | |
return self.calData | |
getCalibrationData.section = 3 | |
def readDefaultsConfig(self): | |
""" | |
Name: U3.readDefaultsConfig( ) | |
Args: None | |
Desc: Reads the power-up defaults stored in flash. | |
""" | |
results = dict() | |
defaults = self.readDefaults(0) | |
results['FIODirection'] = defaults[4] | |
results['FIOState'] = defaults[5] | |
results['FIOAnalog'] = defaults[6] | |
results['EIODirection'] = defaults[8] | |
results['EIOState'] = defaults[9] | |
results['EIOAnalog'] = defaults[10] | |
results['CIODirection'] = defaults[12] | |
results['CIOState'] = defaults[13] | |
results['NumOfTimersEnable'] = defaults[17] | |
results['CounterMask'] = defaults[18] | |
results['PinOffset'] = defaults[19] | |
results['Options'] = defaults[20] | |
defaults = self.readDefaults(1) | |
results['ClockSource'] = defaults[0] | |
results['Divisor'] = defaults[1] | |
results['TMR0Mode'] = defaults[16] | |
results['TMR0ValueL'] = defaults[17] | |
results['TMR0ValueH'] = defaults[18] | |
results['TMR1Mode'] = defaults[20] | |
results['TMR1ValueL'] = defaults[21] | |
results['TMR1ValueH'] = defaults[22] | |
defaults = self.readDefaults(2) | |
results['DAC0'] = struct.unpack( ">H", struct.pack("BB", *defaults[16:18]) )[0] | |
results['DAC1'] = struct.unpack( ">H", struct.pack("BB", *defaults[20:22]) )[0] | |
defaults = self.readDefaults(3) | |
for i in range(16): | |
results["AIN%sNegChannel" % i] = defaults[i] | |
return results | |
readDefaultsConfig.section = 3 | |
def exportConfig(self): | |
""" | |
Name: U3.exportConfig( ) | |
Args: None | |
Desc: Takes the current configuration and puts it into a ConfigParser | |
object. Useful for saving the setup of your U3. | |
""" | |
# Make a new configuration file | |
parser = ConfigParser.SafeConfigParser() | |
# Change optionxform so that options preserve their case. | |
parser.optionxform = str | |
# Local Id and name | |
self.configU3() | |
section = "Identifiers" | |
parser.add_section(section) | |
parser.set(section, "Local ID", str(self.localId)) | |
parser.set(section, "Name", str(self.getName())) | |
parser.set(section, "Device Type", str(self.devType)) | |
# FIO Direction / State | |
section = "FIOs" | |
parser.add_section(section) | |
dirs, states = self.getFeedback( PortDirRead(), PortStateRead() ) | |
parser.set(section, "FIOs Analog", str( self.readRegister(50590) )) | |
parser.set(section, "EIOs Analog", str( self.readRegister(50591) )) | |
for key, value in dirs.items(): | |
parser.set(section, "%s Directions" % key, str(value)) | |
for key, value in states.items(): | |
parser.set(section, "%s States" % key, str(value)) | |
# DACs | |
section = "DACs" | |
parser.add_section(section) | |
dac0 = self.readRegister(5000) | |
dac0 = max(dac0, 0) | |
dac0 = min(dac0, 5) | |
parser.set(section, "DAC0", "%0.2f" % dac0) | |
dac1 = self.readRegister(5002) | |
dac1 = max(dac1, 0) | |
dac1 = min(dac1, 5) | |
parser.set(section, "DAC1", "%0.2f" % dac1) | |
# Timer Clock Configuration | |
section = "Timer Clock Speed Configuration" | |
parser.add_section(section) | |
timerclockconfig = self.configTimerClock() | |
for key, value in timerclockconfig.items(): | |
parser.set(section, key, str(value)) | |
# Timers / Counters | |
section = "Timers And Counters" | |
parser.add_section(section) | |
timerCounterConfig = self.configIO() | |
nte = timerCounterConfig['NumberOfTimersEnabled'] | |
ec0 = timerCounterConfig['EnableCounter0'] | |
ec1 = timerCounterConfig['EnableCounter1'] | |
cpo = timerCounterConfig['TimerCounterPinOffset'] | |
parser.set(section, "NumberTimersEnabled", str(nte) ) | |
parser.set(section, "Counter0Enabled", str(ec0) ) | |
parser.set(section, "Counter1Enabled", str(ec1) ) | |
parser.set(section, "TimerCounterPinOffset", str(cpo) ) | |
for i in range(nte): | |
mode, value = self.readRegister(7100 + (2*i), numReg = 2, format = ">HH") | |
parser.set(section, "Timer%i Mode" % i, str(mode)) | |
parser.set(section, "Timer%i Value" % i, str(value)) | |
return parser | |
exportConfig.section = 3 | |
def loadConfig(self, configParserObj): | |
""" | |
Name: U3.loadConfig( configParserObj ) | |
Args: configParserObj, A Config Parser object to load in | |
Desc: Takes a configuration and updates the U3 to match it. | |
""" | |
parser = configParserObj | |
# Set Identifiers: | |
section = "Identifiers" | |
if parser.has_section(section): | |
if parser.has_option(section, "device type"): | |
if parser.getint(section, "device type") != self.devType: | |
raise Exception("Not a U3 Config file.") | |
if parser.has_option(section, "local id"): | |
self.configU3( LocalID = parser.getint(section, "local id")) | |
if parser.has_option(section, "name"): | |
self.setName( parser.get(section, "name") ) | |
# Set FIOs: | |
section = "FIOs" | |
if parser.has_section(section): | |
fioanalog = 0 | |
eioanalog = 0 | |
fiodirs = 0 | |
eiodirs = 0 | |
ciodirs = 0 | |
fiostates = 0 | |
eiostates = 0 | |
ciostates = 0 | |
if parser.has_option(section, "fios analog"): | |
fioanalog = parser.getint(section, "fios analog") | |
if parser.has_option(section, "eios analog"): | |
eioanalog = parser.getint(section, "eios analog") | |
if parser.has_option(section, "fios directions"): | |
fiodirs = parser.getint(section, "fios directions") | |
if parser.has_option(section, "eios directions"): | |
eiodirs = parser.getint(section, "eios directions") | |
if parser.has_option(section, "cios directions"): | |
ciodirs = parser.getint(section, "cios directions") | |
if parser.has_option(section, "fios states"): | |
fiostates = parser.getint(section, "fios states") | |
if parser.has_option(section, "eios states"): | |
eiostates = parser.getint(section, "eios states") | |
if parser.has_option(section, "cios states"): | |
ciostates = parser.getint(section, "cios states") | |
self.configIO(FIOAnalog = fioanalog, EIOAnalog = eioanalog) | |
self.getFeedback( PortStateWrite([fiostates, eiostates, ciostates]), PortDirWrite([fiodirs, eiodirs, ciodirs]) ) | |
# Set DACs: | |
section = "DACs" | |
if parser.has_section(section): | |
if parser.has_option(section, "dac0"): | |
self.writeRegister(5000, parser.getfloat(section, "dac0")) | |
if parser.has_option(section, "dac1"): | |
self.writeRegister(5002, parser.getfloat(section, "dac1")) | |
# Set Timer Clock Configuration | |
section = "Timer Clock Speed Configuration" | |
if parser.has_section(section): | |
if parser.has_option(section, "timerclockbase") and parser.has_option(section, "timerclockdivisor"): | |
self.configTimerClock(TimerClockBase = parser.getint(section, "timerclockbase"), TimerClockDivisor = parser.getint(section, "timerclockdivisor")) | |
# Set Timers / Counters | |
section = "Timers And Counters" | |
if parser.has_section(section): | |
nte = None | |
c0e = None | |
c1e = None | |
cpo = None | |
if parser.has_option(section, "NumberTimersEnabled"): | |
nte = parser.getint(section, "NumberTimersEnabled") | |
if parser.has_option(section, "TimerCounterPinOffset"): | |
cpo = parser.getint(section, "TimerCounterPinOffset") | |
if parser.has_option(section, "Counter0Enabled"): | |
c0e = parser.getboolean(section, "Counter0Enabled") | |
if parser.has_option(section, "Counter1Enabled"): | |
c1e = parser.getboolean(section, "Counter1Enabled") | |
self.configIO(NumberOfTimersEnabled = nte, EnableCounter1 = c1e, EnableCounter0 = c0e, TimerCounterPinOffset = cpo) | |
mode = None | |
value = None | |
if parser.has_option(section, "timer0 mode"): | |
mode = parser.getint(section, "timer0 mode") | |
if parser.has_option(section, "timer0 value"): | |
value = parser.getint(section, "timer0 value") | |
self.getFeedback( Timer0Config(mode, value) ) | |
if parser.has_option(section, "timer1 mode"): | |
mode = parser.getint(section, "timer1 mode") | |
if parser.has_option(section, "timer1 value"): | |
value = parser.getint(section, "timer1 value") | |
self.getFeedback( Timer1Config(mode, value) ) | |
loadConfig.section = 3 | |
class FeedbackCommand(object): | |
""" | |
The FeedbackCommand class is the base for all the Feedback commands. | |
""" | |
readLen = 0 | |
def handle(self, input): | |
return None | |
class AIN(FeedbackCommand): | |
''' | |
Analog Input Feedback command | |
specify the positive and negative channels to use | |
(0-16, 30 and 31 are possible) | |
also specify whether to turn on longSettle or quick Sample | |
returns 16-bit signed int sample | |
>>> import u3 | |
>>> d = u3.U3() | |
>>> d.debug = True | |
>>> d.getFeedback(u3.AIN(PositiveChannel = 0, NegativeChannel=31, LongSettling=False, QuickSample=False)) | |
Sent: [0x1b, 0xf8, 0x2, 0x0, 0x20, 0x0, 0x0, 0x1, 0x0, 0x1f] | |
Response: [0xab, 0xf8, 0x3, 0x0, 0xaf, 0x0, 0x0, 0x0, 0x0, 0x20, 0x8f, 0x0] | |
[36640] | |
''' | |
def __init__(self, PositiveChannel, NegativeChannel=31, | |
LongSettling=False, QuickSample=False): | |
self.positiveChannel = PositiveChannel | |
self.negativeChannel = NegativeChannel | |
self.longSettling = LongSettling | |
self.quickSample = QuickSample | |
validChannels = range(16) + [30, 31] | |
if PositiveChannel not in validChannels: | |
raise Exception("Invalid Positive Channel specified") | |
if NegativeChannel not in validChannels: | |
raise Exception("Invalid Negative Channel specified") | |
b = PositiveChannel | |
b |= (int(bool(LongSettling)) << 6) | |
b |= (int(bool(QuickSample)) << 7) | |
self.cmdBytes = [ 0x01, b, NegativeChannel ] | |
readLen = 2 | |
def __repr__(self): | |
return "<u3.AIN( PositiveChannel = %s, NegativeChannel = %s, LongSettling = %s, QuickSample = %s )>" % ( self.positiveChannel, self.negativeChannel, self.longSettling, self.quickSample ) | |
def handle(self, input): | |
result = (input[1] << 8) + input[0] | |
return result | |
class WaitShort(FeedbackCommand): | |
''' | |
WaitShort Feedback command | |
specify the number of 128us time increments to wait | |
>>> import u3 | |
>>> d = u3.U3() | |
>>> d.debug = True | |
>>> d.getFeedback(u3.WaitShort(Time = 9)) | |
Sent: [0x9, 0xf8, 0x2, 0x0, 0xe, 0x0, 0x0, 0x5, 0x9, 0x0] | |
Response: [0xfa, 0xf8, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0] | |
[None] | |
''' | |
def __init__(self, Time): | |
self.time = Time % 256 | |
self.cmdBytes = [ 5, Time % 256 ] | |
def __repr__(self): | |
return "<u3.WaitShort( Time = %s )>" % self.time | |
class WaitLong(FeedbackCommand): | |
''' | |
WaitLong Feedback command | |
specify the number of 32ms time increments to wait | |
>>> import u3 | |
>>> d = u3.U3() | |
>>> d.debug = True | |
>>> d.getFeedback(u3.WaitLong(Time = 70)) | |
Sent: [0x47, 0xf8, 0x2, 0x0, 0x4c, 0x0, 0x0, 0x6, 0x46, 0x0] | |
Response: [0xfa, 0xf8, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0] | |
[None] | |
''' | |
def __init__(self, Time): | |
self.time = Time % 256 | |
self.cmdBytes = [ 6, Time % 256 ] | |
def __repr__(self): | |
return "<u3.WaitLong( Time = %s )>" % self.time | |
class LED(FeedbackCommand): | |
''' | |
LED Toggle | |
specify whether the LED should be on or off by truth value | |
1 or True = On, 0 or False = Off | |
>>> import u3 | |
>>> d = u3.U3() | |
>>> d.debug = True | |
>>> d.getFeedback(u3.LED(State = False)) | |
Sent: [0x4, 0xf8, 0x2, 0x0, 0x9, 0x0, 0x0, 0x9, 0x0, 0x0] | |
Response: [0xfa, 0xf8, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0] | |
[None] | |
>>> d.getFeedback(u3.LED(State = True)) | |
Sent: [0x5, 0xf8, 0x2, 0x0, 0xa, 0x0, 0x0, 0x9, 0x1, 0x0] | |
Response: [0xfa, 0xf8, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0] | |
[None] | |
''' | |
def __init__(self, State): | |
self.state = State | |
self.cmdBytes = [ 9, int(bool(State)) ] | |
def __repr__(self): | |
return "<u3.LED( State = %s )>" % self.state | |
class BitStateRead(FeedbackCommand): | |
''' | |
BitStateRead Feedback command | |
read the state of a single bit of digital I/O. Only digital | |
lines return valid readings. | |
IONumber: 0-7=FIO, 8-15=EIO, 16-19=CIO | |
return 0 or 1 | |
>>> import u3 | |
>>> d = u3.U3() | |
>>> d.debug = True | |
>>> d.getFeedback(u3.BitStateRead(IONumber = 5)) | |
Sent: [0xa, 0xf8, 0x2, 0x0, 0xf, 0x0, 0x0, 0xa, 0x5, 0x0] | |
Response: [0xfb, 0xf8, 0x2, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x1] | |
[1] | |
''' | |
def __init__(self, IONumber): | |
self.ioNumber = IONumber | |
self.cmdBytes = [ 10, IONumber % 20 ] | |
readLen = 1 | |
def __repr__(self): | |
return "<u3.BitStateRead( IONumber = %s )>" % self.ioNumber | |
def handle(self, input): | |
return int(bool(input[0])) | |
class BitStateWrite(FeedbackCommand): | |
''' | |
BitStateWrite Feedback command | |
write a single bit of digital I/O. The direction of the | |
specified line is forced to output. | |
IONumber: 0-7=FIO, 8-15=EIO, 16-19=CIO | |
State: 0 or 1 | |
>>> import u3 | |
>>> d = u3.U3() | |
>>> d.debug = True | |
>>> d.getFeedback(u3.BitStateWrite(IONumber = 5, State = 0)) | |
Sent: [0xb, 0xf8, 0x2, 0x0, 0x10, 0x0, 0x0, 0xb, 0x5, 0x0] | |
Response: [0xfa, 0xf8, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0] | |
[None] | |
''' | |
def __init__(self, IONumber, State): | |
self.ioNumber = IONumber | |
self.state = State | |
self.cmdBytes = [ 11, (IONumber % 20) + (int(bool(State)) << 7) ] | |
def __repr__(self): | |
return "<u3.BitStateWrite( IONumber = %s, State = %s )>" % (self.ioNumber, self.state) | |
class BitDirRead(FeedbackCommand): | |
''' | |
Read the digital direction of one I/O | |
IONumber: 0-7=FIO, 8-15=EIO, 16-19=CIO | |
returns 1 = Output, 0 = Input | |
>>> import u3 | |
>>> d = u3.U3() | |
>>> d.debug = True | |
>>> d.getFeedback(u3.BitDirRead(IONumber = 5)) | |
Sent: [0xc, 0xf8, 0x2, 0x0, 0x11, 0x0, 0x0, 0xc, 0x5, 0x0] | |
Response: [0xfb, 0xf8, 0x2, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x1] | |
[1] | |
''' | |
def __init__(self, IONumber): | |
self.ioNumber = IONumber | |
self.cmdBytes = [ 12, IONumber % 20 ] | |
readLen = 1 | |
def __repr__(self): | |
return "<u3.BitDirRead( IONumber = %s )>" % self.ioNumber | |
def handle(self, input): | |
return int(bool(input[0])) | |
class BitDirWrite(FeedbackCommand): | |
''' | |
BitDirWrite Feedback command | |
Set the digital direction of one I/O | |
IONumber: 0-7=FIO, 8-15=EIO, 16-19=CIO | |
Direction: 1 = Output, 0 = Input | |
>>> import u3 | |
>>> d = u3.U3() | |
>>> d.debug = True | |
>>> d.getFeedback(u3.BitDirWrite(IONumber = 5, Direction = 0)) | |
Sent: [0xd, 0xf8, 0x2, 0x0, 0x12, 0x0, 0x0, 0xd, 0x5, 0x0] | |
Response: [0xfa, 0xf8, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0] | |
[None] | |
''' | |
def __init__(self, IONumber, Direction): | |
self.ioNumber = IONumber | |
self.direction = Direction | |
self.cmdBytes = [ 13, (IONumber % 20) + (int(bool(Direction)) << 7) ] | |
def __repr__(self): | |
return "<u3.BitDirWrite( IONumber = %s, Direction = %s )>" % (self.ioNumber, self.direction) | |
class PortStateRead(FeedbackCommand): | |
""" | |
PortStateRead Feedback command | |
Reads the state of all digital I/O. | |
>>> import u3 | |
>>> d = u3.U3() | |
>>> d.debug = True | |
>>> d.getFeedback(u3.PortStateRead()) | |
Sent: [0x14, 0xf8, 0x1, 0x0, 0x1a, 0x0, 0x0, 0x1a] | |
Response: [0xeb, 0xf8, 0x3, 0x0, 0xee, 0x1, 0x0, 0x0, 0x0, 0xe0, 0xff, 0xf] | |
[{'CIO': 15, 'FIO': 224, 'EIO': 255}] | |
""" | |
def __init__(self): | |
self.cmdBytes = [ 26 ] | |
readLen = 3 | |
def handle(self, input): | |
return {'FIO' : input[0], 'EIO' : input[1], 'CIO' : input[2] } | |
def __repr__(self): | |
return "<u3.PortStateRead()>" | |
class PortStateWrite(FeedbackCommand): | |
""" | |
PortStateWrite Feedback command | |
State: A list of 3 bytes representing FIO, EIO, CIO | |
WriteMask: A list of 3 bytes, representing which to update. | |
The Default is all ones. | |
>>> import u3 | |
>>> d = u3.U3() | |
>>> d.debug = True | |
>>> d.getFeedback(u3.PortStateWrite(State = [0xab, 0xcd, 0xef], WriteMask = [0xff, 0xff, 0xff])) | |
Sent: [0x81, 0xf8, 0x4, 0x0, 0x7f, 0x5, 0x0, 0x1b, 0xff, 0xff, 0xff, 0xab, 0xcd, 0xef] | |
Response: [0xfa, 0xf8, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0] | |
[None] | |
""" | |
def __init__(self, State, WriteMask = [0xff, 0xff, 0xff]): | |
self.state = State | |
self.writeMask = WriteMask | |
self.cmdBytes = [ 27 ] + WriteMask + State | |
def __repr__(self): | |
return "<u3.PortStateWrite( State = %s, WriteMask = %s )>" % (self.state, self.writeMask) | |
class PortDirRead(FeedbackCommand): | |
""" | |
PortDirRead Feedback command | |
Reads the direction of all digital I/O. | |
>>> import u3 | |
>>> d = u3.U3() | |
>>> d.debug = True | |
>>> d.getFeedback(u3.PortDirRead()) | |
Sent: [0x16, 0xf8, 0x1, 0x0, 0x1c, 0x0, 0x0, 0x1c] | |
Response: [0xfb, 0xf8, 0x3, 0x0, 0xfe, 0x1, 0x0, 0x0, 0x0, 0xf0, 0xff, 0xf] | |
[{'CIO': 15, 'FIO': 240, 'EIO': 255}] | |
""" | |
def __init__(self): | |
self.cmdBytes = [ 28 ] | |
readLen = 3 | |
def __repr__(self): | |
return "<u3.PortDirRead()>" | |
def handle(self, input): | |
return {'FIO' : input[0], 'EIO' : input[1], 'CIO' : input[2] } | |
class PortDirWrite(FeedbackCommand): | |
""" | |
PortDirWrite Feedback command | |
Direction: A list of 3 bytes representing FIO, EIO, CIO | |
WriteMask: A list of 3 bytes, representing which to update. Default is all ones. | |
>>> import u3 | |
>>> d = u3.U3() | |
>>> d.debug = True | |
>>> d.getFeedback(u3.PortDirWrite(Direction = [0xaa, 0xcc, 0xff], WriteMask = [0xff, 0xff, 0xff])) | |
Sent: [0x91, 0xf8, 0x4, 0x0, 0x8f, 0x5, 0x0, 0x1d, 0xff, 0xff, 0xff, 0xaa, 0xcc, 0xff] | |
Response: [0xfa, 0xf8, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0] | |
[None] | |
""" | |
def __init__(self, Direction, WriteMask = [ 0xff, 0xff, 0xff]): | |
self.direction = Direction | |
self.writeMask = WriteMask | |
self.cmdBytes = [ 29 ] + WriteMask + Direction | |
def __repr__(self): | |
return "<u3.PortDirWrite( Direction = %s, WriteMask = %s )>" % (self.direction, self.writeMask) | |
class DAC8(FeedbackCommand): | |
''' | |
8-bit DAC Feedback command | |
Controls a single analog output | |
Dac: 0 or 1 | |
Value: 0-255 | |
>>> import u3 | |
>>> d = u3.U3() | |
>>> d.debug = True | |
>>> d.getFeedback(u3.DAC8(Dac = 0, Value = 0x55)) | |
Sent: [0x72, 0xf8, 0x2, 0x0, 0x77, 0x0, 0x0, 0x22, 0x55, 0x0] | |
Response: [0xfa, 0xf8, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0] | |
[None] | |
''' | |
def __init__(self, Dac, Value): | |
self.dac = Dac | |
self.value = Value % 256 | |
self.cmdBytes = [ 34 + (Dac % 2), Value % 256 ] | |
def __repr__(self): | |
return "<u3.DAC8( Dac = %s, Value = %s )>" % (self.dac, self.value) | |
class DAC0_8(DAC8): | |
""" | |
8-bit DAC Feedback command for DAC0 | |
Controls DAC0 in 8-bit mode. | |
Value: 0-255 | |
>>> import u3 | |
>>> d = u3.U3() | |
>>> d.debug = True | |
>>> d.getFeedback(u3.DAC0_8(Value = 0x33)) | |
Sent: [0x50, 0xf8, 0x2, 0x0, 0x55, 0x0, 0x0, 0x22, 0x33, 0x0] | |
Response: [0xfa, 0xf8, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0] | |
[None] | |
""" | |
def __init__(self, Value): | |
DAC8.__init__(self, 0, Value) | |
def __repr__(self): | |
return "<u3.DAC0_8( Value = %s )>" % self.value | |
class DAC1_8(DAC8): | |
""" | |
8-bit DAC Feedback command for DAC1 | |
Controls DAC1 in 8-bit mode. | |
Value: 0-255 | |
>>> import u3 | |
>>> d = u3.U3() | |
>>> d.debug = True | |
>>> d.getFeedback(u3.DAC1_8(Value = 0x22)) | |
Sent: [0x40, 0xf8, 0x2, 0x0, 0x45, 0x0, 0x0, 0x23, 0x22, 0x0] | |
Response: [0xfa, 0xf8, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0] | |
[None] | |
""" | |
def __init__(self, Value): | |
DAC8.__init__(self, 1, Value) | |
def __repr__(self): | |
return "<u3.DAC1_8( Value = %s )>" % self.value | |
class DAC16(FeedbackCommand): | |
''' | |
16-bit DAC Feedback command | |
Controls a single analog output | |
Dac: 0 or 1 | |
Value: 0-65535 | |
>>> import u3 | |
>>> d = u3.U3() | |
>>> d.debug = True | |
>>> d.getFeedback(u3.DAC16(Dac = 0, Value = 0x5566)) | |
Sent: [0xdc, 0xf8, 0x2, 0x0, 0xe1, 0x0, 0x0, 0x26, 0x66, 0x55] | |
Response: [0xfa, 0xf8, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0] | |
[None] | |
''' | |
def __init__(self, Dac, Value): | |
self.dac = Dac | |
self.value = Value | |
self.cmdBytes = [ 38 + (Dac % 2), Value % 256, Value >> 8 ] | |
def __repr__(self): | |
return "<u3.DAC16( Dac = %s, Value = %s )>" % (self.dac, self.value) | |
class DAC0_16(DAC16): | |
""" | |
16-bit DAC Feedback command for DAC0 | |
Controls DAC0 in 16-bit mode. | |
Value: 0-65535 | |
>>> import u3 | |
>>> d = u3.U3() | |
>>> d.debug = True | |
>>> d.getFeedback(u3.DAC0_16(Value = 0x1122)) | |
Sent: [0x54, 0xf8, 0x2, 0x0, 0x59, 0x0, 0x0, 0x26, 0x22, 0x11] | |
Response: [0xfa, 0xf8, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0] | |
[None] | |
""" | |
def __init__(self, Value): | |
DAC16.__init__(self, 0, Value) | |
def __repr__(self): | |
return "<u3.DAC0_16( Value = %s )>" % self.value | |
class DAC1_16(DAC16): | |
""" | |
16-bit DAC Feedback command for DAC1 | |
Controls DAC1 in 16-bit mode. | |
Value: 0-65535 | |
>>> import u3 | |
>>> d = u3.U3() | |
>>> d.debug = True | |
>>> d.getFeedback(u3.DAC1_16(Value = 0x2233)) | |
Sent: [0x77, 0xf8, 0x2, 0x0, 0x7c, 0x0, 0x0, 0x27, 0x33, 0x22] | |
Response: [0xfa, 0xf8, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0] | |
[None] | |
""" | |
def __init__(self, Value): | |
DAC16.__init__(self, 1, Value) | |
def __repr__(self): | |
return "<u3.DAC1_16( Value = %s )>" % self.value | |
class Timer(FeedbackCommand): | |
""" | |
For reading the value of the Timer. It provides the ability to update/reset | |
a given timer, and read the timer value. | |
(Section 5.2.5.14 of the User's Guide) | |
timer: Either 0 or 1 for timer 0 or timer 1 | |
UpdateReset: Set True if you want to update the value | |
Value: Only updated if the UpdateReset bit is 1. The meaning of this | |
parameter varies with the timer mode. | |
Mode: Set to the timer mode to handle any special processing. See classes | |
QuadratureInputTimer and TimerStopInput1. | |
Returns an unsigned integer of the timer value, unless Mode has been | |
specified and there are special return values. See Section 2.9.1 for | |
expected return values. | |
>>> import u3 | |
>>> d = u3.U3() | |
>>> d.debug = True | |
>>> d.configIO(NumberOfTimersEnabled = 1) | |
Sent: [0x49, 0xf8, 0x3, 0xb, 0x42, 0x0, 0x1, 0x0, 0x41, 0x0, 0x0, 0x0] | |
Response: [0x57, 0xf8, 0x3, 0xb, 0x50, 0x0, 0x0, 0x0, 0x41, 0x0, 0xf, 0x0] | |
{'NumberOfTimersEnabled': 1, 'TimerCounterPinOffset': 4, 'DAC1Enable': 0, 'FIOAnalog': 15, 'EIOAnalog': 0, 'TimerCounterConfig': 65, 'EnableCounter1': False, 'EnableCounter0': False} | |
>>> d.getFeedback(u3.Timer(timer = 0, UpdateReset = False, Value = 0, Mode = None)) | |
Sent: [0x26, 0xf8, 0x3, 0x0, 0x2a, 0x0, 0x0, 0x2a, 0x0, 0x0, 0x0, 0x0] | |
Response: [0xfc, 0xf8, 0x4, 0x0, 0xfe, 0x1, 0x0, 0x0, 0x0, 0x63, 0xdd, 0x4c, 0x72, 0x0] | |
[1917640035] | |
""" | |
def __init__(self, timer, UpdateReset = False, Value=0, Mode = None): | |
self.timer = timer | |
self.updateReset = UpdateReset | |
self.value = Value | |
self.mode = Mode | |
if timer != 0 and timer != 1: | |
raise LabJackException("Timer should be either 0 or 1.") | |
if UpdateReset and Value == None: | |
raise LabJackException("UpdateReset set but no value.") | |
self.cmdBytes = [ (42 + (2*timer)), UpdateReset, Value % 256, Value >> 8 ] | |
readLen = 4 | |
def __repr__(self): | |
return "<u3.Timer( timer = %s, UpdateReset = %s, Value = %s, Mode = %s )>" % (self.timer, self.updateReset, self.value, self.mode) | |
def handle(self, input): | |
inStr = struct.pack('B' * len(input), *input) | |
if self.mode == 8: | |
return struct.unpack('<i', inStr )[0] | |
elif self.mode == 9: | |
maxCount, current = struct.unpack('<HH', inStr ) | |
return current, maxCount | |
else: | |
return struct.unpack('<I', inStr )[0] | |
class Timer0(Timer): | |
""" | |
For reading the value of the Timer0. It provides the ability to | |
update/reset Timer0, and read the timer value. | |
(Section 5.2.5.14 of the User's Guide) | |
UpdateReset: Set True if you want to update the value | |
Value: Only updated if the UpdateReset bit is 1. The meaning of this | |
parameter varies with the timer mode. | |
Mode: Set to the timer mode to handle any special processing. See classes | |
QuadratureInputTimer and TimerStopInput1. | |
>>> import u3 | |
>>> d = u3.U3() | |
>>> d.debug = True | |
>>> d.configIO(NumberOfTimersEnabled = 1) | |
Sent: [0x49, 0xf8, 0x3, 0xb, 0x42, 0x0, 0x1, 0x0, 0x41, 0x0, 0x0, 0x0] | |
Response: [0x57, 0xf8, 0x3, 0xb, 0x50, 0x0, 0x0, 0x0, 0x41, 0x0, 0xf, 0x0] | |
{'NumberOfTimersEnabled': 1, 'TimerCounterPinOffset': 4, 'DAC1Enable': 0, 'FIOAnalog': 15, 'EIOAnalog': 0, 'TimerCounterConfig': 65, 'EnableCounter1': False, 'EnableCounter0': False} | |
>>> d.getFeedback(u3.Timer0(UpdateReset = False, Value = 0, Mode = None)) | |
Sent: [0x26, 0xf8, 0x3, 0x0, 0x2a, 0x0, 0x0, 0x2a, 0x0, 0x0, 0x0, 0x0] | |
Response: [0x51, 0xf8, 0x4, 0x0, 0x52, 0x2, 0x0, 0x0, 0x0, 0xf6, 0x90, 0x46, 0x86, 0x0] | |
[2252771574] | |
""" | |
def __init__(self, UpdateReset = False, Value = 0, Mode = None): | |
Timer.__init__(self, 0, UpdateReset, Value, Mode) | |
def __repr__(self): | |
return "<u3.Timer0( UpdateReset = %s, Value = %s, Mode = %s )>" % (self.updateReset, self.value, self.mode) | |
class Timer1(Timer): | |
""" | |
For reading the value of the Timer1. It provides the ability to | |
update/reset Timer1, and read the timer value. | |
(Section 5.2.5.14 of the User's Guide) | |
UpdateReset: Set True if you want to update the value | |
Value: Only updated if the UpdateReset bit is 1. The meaning of this | |
parameter varies with the timer mode. | |
Mode: Set to the timer mode to handle any special processing. See classes | |
QuadratureInputTimer and TimerStopInput1. | |
>>> import u3 | |
>>> d = u3.U3() | |
>>> d.debug = True | |
>>> d.configIO(NumberOfTimersEnabled = 2) | |
Sent: [0x4a, 0xf8, 0x3, 0xb, 0x43, 0x0, 0x1, 0x0, 0x42, 0x0, 0x0, 0x0] | |
Response: [0x58, 0xf8, 0x3, 0xb, 0x51, 0x0, 0x0, 0x0, 0x42, 0x0, 0xf, 0x0] | |
{'NumberOfTimersEnabled': 2, 'TimerCounterPinOffset': 4, 'DAC1Enable': 0, 'FIOAnalog': 15, 'EIOAnalog': 0, 'TimerCounterConfig': 66, 'EnableCounter1': False, 'EnableCounter0': False} | |
>>> d.getFeedback(u3.Timer1(UpdateReset = False, Value = 0, Mode = None)) | |
Sent: [0x28, 0xf8, 0x3, 0x0, 0x2c, 0x0, 0x0, 0x2c, 0x0, 0x0, 0x0, 0x0] | |
Response: [0x8d, 0xf8, 0x4, 0x0, 0x8e, 0x2, 0x0, 0x0, 0x0, 0xf3, 0x31, 0xd0, 0x9a, 0x0] | |
[2597335539] | |
""" | |
def __init__(self, UpdateReset = False, Value = 0, Mode = None): | |
Timer.__init__(self, 1, UpdateReset, Value, Mode) | |
def __repr__(self): | |
return "<u3.Timer1( UpdateReset = %s, Value = %s, Mode = %s )>" % (self.updateReset, self.value, self.mode) | |
class QuadratureInputTimer(Timer): | |
""" | |
For reading Quadrature input timers. They are special because their values | |
are signed. | |
(Section 2.9.1.8 of the User's Guide) | |
Args: | |
UpdateReset: Set True if you want to reset the counter. | |
Value: Set to 0, and UpdateReset to True to reset the counter. | |
Returns a signed integer. | |
>>> import u3 | |
>>> d = u3.U3() | |
>>> d.debug = True | |
>>> d.configIO(NumberOfTimersEnabled = 2) | |
Sent: [0x4a, 0xf8, 0x3, 0xb, 0x43, 0x0, 0x1, 0x0, 0x42, 0x0, 0x0, 0x0] | |
Response: [0x58, 0xf8, 0x3, 0xb, 0x51, 0x0, 0x0, 0x0, 0x42, 0x0, 0xf, 0x0] | |
{'NumberOfTimersEnabled': 2, 'TimerCounterPinOffset': 4, 'DAC1Enable': 0, 'FIOAnalog': 15, 'EIOAnalog': 0, 'TimerCounterConfig': 66, 'EnableCounter1': False, 'EnableCounter0': False} | |
>>> # Setup the two timers to be quadrature | |
>>> d.getFeedback(u3.Timer0Config(8), u3.Timer1Config(8)) | |
Sent: [0x66, 0xf8, 0x5, 0x0, 0x68, 0x0, 0x0, 0x2b, 0x8, 0x0, 0x0, 0x2d, 0x8, 0x0, 0x0, 0x0] | |
Response: [0xfa, 0xf8, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0] | |
[None, None] | |
>>> # Read the value | |
[0] | |
>>> d.getFeedback(u3.QuadratureInputTimer()) | |
Sent: [0x26, 0xf8, 0x3, 0x0, 0x2a, 0x0, 0x0, 0x2a, 0x0, 0x0, 0x0, 0x0] | |
Response: [0xf5, 0xf8, 0x4, 0x0, 0xf5, 0x3, 0x0, 0x0, 0x0, 0xf8, 0xff, 0xff, 0xff, 0x0] | |
[-8] | |
>>> d.getFeedback(u3.QuadratureInputTimer()) | |
Sent: [0x26, 0xf8, 0x3, 0x0, 0x2a, 0x0, 0x0, 0x2a, 0x0, 0x0, 0x0, 0x0] | |
Response: [0x9, 0xf8, 0x4, 0x0, 0xc, 0x0, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x0] | |
[12] | |
""" | |
def __init__(self, UpdateReset = False, Value = 0): | |
Timer.__init__(self, 0, UpdateReset, Value, Mode = 8) | |
def __repr__(self): | |
return "<u3.QuadratureInputTimer( UpdateReset = %s, Value = %s )>" % (self.updateReset, self.value) | |
class TimerStopInput1(Timer1): | |
""" | |
For reading a stop input timer. They are special because the value returns | |
the current edge count and the stop value. | |
(Section 2.9.1.9 of the User's Guide) | |
Args: | |
UpdateReset: Set True if you want to update the value. | |
Value: The stop value. Only updated if the UpdateReset bit is 1. | |
Returns a tuple where the first value is current edge count, and the second | |
value is the stop value. | |
>>> import u3 | |
>>> d = u3.U3() | |
>>> d.debug = True | |
>>> d.configIO(NumberOfTimersEnabled = 2) | |
Sent: [0x4a, 0xf8, 0x3, 0xb, 0x43, 0x0, 0x1, 0x0, 0x42, 0x0, 0x0, 0x0] | |
Response: [0x58, 0xf8, 0x3, 0xb, 0x51, 0x0, 0x0, 0x0, 0x42, 0x0, 0xf, 0x0] | |
{'NumberOfTimersEnabled': 2, 'TimerCounterPinOffset': 4, 'DAC1Enable': 0, 'FIOAnalog': 15, 'EIOAnalog': 0, 'TimerCounterConfig': 66, 'EnableCounter1': False, 'EnableCounter0': False} | |
>>> # Setup the timer to be Stop Input | |
>>> d.getFeedback(u3.Timer1Config(9, Value = 30)) | |
Sent: [0x50, 0xf8, 0x3, 0x0, 0x54, 0x0, 0x0, 0x2d, 0x9, 0x1e, 0x0, 0x0] | |
Response: [0xfa, 0xf8, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0] | |
[None] | |
>>> d.getFeedback(u3.TimerStopInput1()) | |
Sent: [0x28, 0xf8, 0x3, 0x0, 0x2c, 0x0, 0x0, 0x2c, 0x0, 0x0, 0x0, 0x0] | |
Response: [0x1b, 0xf8, 0x4, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x0] | |
[(0, 0)] | |
""" | |
def __init__(self, UpdateReset = False, Value = 0): | |
Timer.__init__(self, 1, UpdateReset, Value, Mode = 9) | |
def __repr__(self): | |
return "<u3.TimerStopInput1( UpdateReset = %s, Value = %s )>" % (self.updateReset, self.value) | |
class TimerConfig(FeedbackCommand): | |
""" | |
This IOType configures a particular timer. | |
timer = # of the timer to configure | |
TimerMode = See Section 2.9 for more information about the available modes. | |
Value = The meaning of this parameter varies with the timer mode. | |
>>> import u3 | |
>>> d = u3.U3() | |
>>> d.debug = True | |
>>> d.configIO(NumberOfTimersEnabled = 1) | |
Sent: [0x49, 0xf8, 0x3, 0xb, 0x42, 0x0, 0x1, 0x0, 0x41, 0x0, 0x0, 0x0] | |
Response: [0x57, 0xf8, 0x3, 0xb, 0x50, 0x0, 0x0, 0x0, 0x41, 0x0, 0xf, 0x0] | |
{'NumberOfTimersEnabled': 1, 'TimerCounterPinOffset': 4, 'DAC1Enable': 0, 'FIOAnalog': 15, 'EIOAnalog': 0, 'TimerCounterConfig': 65, 'EnableCounter1': False, 'EnableCounter0': False} | |
>>> d.getFeedback(u3.TimerConfig(timer = 0, TimerMode = 0, Value = 0)) | |
Sent: [0x27, 0xf8, 0x3, 0x0, 0x2b, 0x0, 0x0, 0x2b, 0x0, 0x0, 0x0, 0x0] | |
Response: [0xfa, 0xf8, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0] | |
[None] | |
>>> d.getFeedback(u3.TimerConfig(timer = 0, TimerMode = 0, Value = 65535)) | |
Sent: [0x27, 0xf8, 0x3, 0x0, 0x29, 0x2, 0x0, 0x2b, 0x0, 0xff, 0xff, 0x0] | |
Response: [0xfa, 0xf8, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0] | |
[None] | |
""" | |
def __init__(self, timer, TimerMode, Value=0): | |
'''Creates command bytes for configureing a Timer''' | |
#Conditions come from pages 33-34 of user's guide | |
if timer != 0 and timer != 1: | |
raise LabJackException("Timer should be either 0 or 1.") | |
if TimerMode > 14 or TimerMode < 0: | |
raise LabJackException("Invalid Timer Mode.") | |
self.timer = timer | |
self.timerMode = TimerMode | |
self.value = Value | |
self.cmdBytes = [43 + (timer * 2), TimerMode, Value % 256, Value >> 8] | |
def __repr__(self): | |
return "<u3.TimerConfig( timer = %s, TimerMode = %s, Value = %s )>" % (self.timer, self.timerMode, self.value) | |
class Timer0Config(TimerConfig): | |
""" | |
This IOType configures Timer0. | |
TimerMode = See Section 2.9 for more information about the available modes. | |
Value = The meaning of this parameter varies with the timer mode. | |
>>> import u3 | |
>>> d = u3.U3() | |
>>> d.debug = True | |
>>> d.configIO(NumberOfTimersEnabled = 1) | |
Sent: [0x49, 0xf8, 0x3, 0xb, 0x42, 0x0, 0x1, 0x0, 0x41, 0x0, 0x0, 0x0] | |
Response: [0x57, 0xf8, 0x3, 0xb, 0x50, 0x0, 0x0, 0x0, 0x41, 0x0, 0xf, 0x0] | |
{'NumberOfTimersEnabled': 1, 'TimerCounterPinOffset': 4, 'DAC1Enable': 0, 'FIOAnalog': 15, 'EIOAnalog': 0, 'TimerCounterConfig': 65, 'EnableCounter1': False, 'EnableCounter0': False} | |
>>> d.getFeedback(u3.Timer0Config(TimerMode = 1, Value = 0)) | |
Sent: [0x28, 0xf8, 0x3, 0x0, 0x2c, 0x0, 0x0, 0x2b, 0x1, 0x0, 0x0, 0x0] | |
Response: [0xfa, 0xf8, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0] | |
[None] | |
>>> d.getFeedback(u3.Timer0Config(TimerMode = 1, Value = 65535)) | |
Sent: [0x28, 0xf8, 0x3, 0x0, 0x2a, 0x2, 0x0, 0x2b, 0x1, 0xff, 0xff, 0x0] | |
Response: [0xfa, 0xf8, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0] | |
[None] | |
""" | |
def __init__(self, TimerMode, Value = 0): | |
TimerConfig.__init__(self, 0, TimerMode, Value) | |
def __repr__(self): | |
return "<u3.Timer0Config( TimerMode = %s, Value = %s )>" % (self.timerMode, self.value) | |
class Timer1Config(TimerConfig): | |
""" | |
This IOType configures Timer1. | |
TimerMode = See Section 2.9 for more information about the available modes. | |
Value = The meaning of this parameter varies with the timer mode. | |
>>> import u3 | |
>>> d = u3.U3() | |
>>> d.debug = True | |
>>> d.configIO(NumberOfTimersEnabled = 2) | |
Sent: [0x4a, 0xf8, 0x3, 0xb, 0x43, 0x0, 0x1, 0x0, 0x42, 0x0, 0x0, 0x0] | |
Response: [0x58, 0xf8, 0x3, 0xb, 0x51, 0x0, 0x0, 0x0, 0x42, 0x0, 0xf, 0x0] | |
{'NumberOfTimersEnabled': 2, 'TimerCounterPinOffset': 4, 'DAC1Enable': 0, 'FIOAnalog': 15, 'EIOAnalog': 0, 'TimerCounterConfig': 66, 'EnableCounter1': False, 'EnableCounter0': False} | |
>>> d.getFeedback(u3.Timer1Config(TimerMode = 6, Value = 1)) | |
Sent: [0x30, 0xf8, 0x3, 0x0, 0x34, 0x0, 0x0, 0x2d, 0x6, 0x1, 0x0, 0x0] | |
Response: [0xfa, 0xf8, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0] | |
[None] | |
""" | |
def __init__(self, TimerMode, Value = 0): | |
TimerConfig.__init__(self, 1, TimerMode, Value) | |
def __repr__(self): | |
return "<u3.Timer1Config( TimerMode = %s, Value = %s )>" % (self.timerMode, self.value) | |
class Counter(FeedbackCommand): | |
''' | |
Counter Feedback command | |
Reads a hardware counter, optionally resetting it | |
counter: 0 or 1 | |
Reset: True ( or 1 ) = Reset, False ( or 0 ) = Don't Reset | |
Returns the current count from the counter if enabled. If reset, | |
this is the value before the reset. | |
>>> import u3 | |
>>> d = u3.U3() | |
>>> d.debug = True | |
>>> d.configIO(EnableCounter0 = True, FIOAnalog = 15) | |
Sent: [0x5f, 0xf8, 0x3, 0xb, 0x58, 0x0, 0x5, 0x0, 0x44, 0x0, 0xf, 0x0] | |
Response: [0x5a, 0xf8, 0x3, 0xb, 0x53, 0x0, 0x0, 0x0, 0x44, 0x0, 0xf, 0x0] | |
{'NumberOfTimersEnabled': 0, 'TimerCounterPinOffset': 4, 'DAC1Enable': 0, 'FIOAnalog': 15, 'EIOAnalog': 0, 'TimerCounterConfig': 68, 'EnableCounter1': False, 'EnableCounter0': True} | |
>>> d.getFeedback(u3.Counter(counter = 0, Reset = False)) | |
Sent: [0x31, 0xf8, 0x2, 0x0, 0x36, 0x0, 0x0, 0x36, 0x0, 0x0] | |
Response: [0xfc, 0xf8, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0] | |
[0] | |
>>> # Tap a ground wire to counter 0 | |
>>> d.getFeedback(u3.Counter(counter = 0, Reset = False)) | |
Sent: [0x31, 0xf8, 0x2, 0x0, 0x36, 0x0, 0x0, 0x36, 0x0, 0x0] | |
Response: [0xe9, 0xf8, 0x4, 0x0, 0xec, 0x0, 0x0, 0x0, 0x0, 0xe8, 0x4, 0x0, 0x0, 0x0] | |
[1256] | |
''' | |
def __init__(self, counter, Reset = False): | |
self.counter = counter | |
self.reset = Reset | |
self.cmdBytes = [ 54 + (counter % 2), int(bool(Reset))] | |
readLen = 4 | |
def __repr__(self): | |
return "<u3.Counter( counter = %s, Reset = %s )>" % (self.counter, self.reset) | |
def handle(self, input): | |
inStr = ''.join([chr(x) for x in input]) | |
return struct.unpack('<I', inStr )[0] | |
class Counter0(Counter): | |
''' | |
Counter0 Feedback command | |
Reads hardware counter0, optionally resetting it | |
Reset: True ( or 1 ) = Reset, False ( or 0 ) = Don't Reset | |
Returns the current count from the counter if enabled. If reset, | |
this is the value before the reset. | |
>>> import u3 | |
>>> d = u3.U3() | |
>>> d.debug = True | |
>>> d.configIO(EnableCounter0 = True, FIOAnalog = 15) | |
Sent: [0x5f, 0xf8, 0x3, 0xb, 0x58, 0x0, 0x5, 0x0, 0x44, 0x0, 0xf, 0x0] | |
Response: [0x5a, 0xf8, 0x3, 0xb, 0x53, 0x0, 0x0, 0x0, 0x44, 0x0, 0xf, 0x0] | |
{'NumberOfTimersEnabled': 0, 'TimerCounterPinOffset': 4, 'DAC1Enable': 0, 'FIOAnalog': 15, 'EIOAnalog': 0, 'TimerCounterConfig': 68, 'EnableCounter1': False, 'EnableCounter0': True} | |
>>> d.getFeedback(u3.Counter0( Reset = False ) ) | |
Sent: [0x31, 0xf8, 0x2, 0x0, 0x36, 0x0, 0x0, 0x36, 0x0, 0x0] | |
Response: [0xfc, 0xf8, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0] | |
[0] | |
>>> # Tap a ground wire to counter 0 | |
>>> d.getFeedback(u3.Counter0(Reset = False)) | |
Sent: [0x31, 0xf8, 0x2, 0x0, 0x36, 0x0, 0x0, 0x36, 0x0, 0x0] | |
Response: [0xe, 0xf8, 0x4, 0x0, 0x11, 0x0, 0x0, 0x0, 0x0, 0x11, 0x0, 0x0, 0x0, 0x0] | |
[17] | |
>>> # Tap a ground wire to counter 0 | |
>>> d.getFeedback(u3.Counter0(Reset = False)) | |
Sent: [0x31, 0xf8, 0x2, 0x0, 0x36, 0x0, 0x0, 0x36, 0x0, 0x0] | |
Response: [0x19, 0xf8, 0x4, 0x0, 0x1c, 0x0, 0x0, 0x0, 0x0, 0xb, 0x11, 0x0, 0x0, 0x0] | |
[4363] | |
''' | |
def __init__(self, Reset = False): | |
Counter.__init__(self, 0, Reset) | |
def __repr__(self): | |
return "<u3.Counter0( Reset = %s )>" % self.reset | |
class Counter1(Counter): | |
''' | |
Counter1 Feedback command | |
Reads hardware counter1, optionally resetting it | |
Reset: True ( or 1 ) = Reset, False ( or 0 ) = Don't Reset | |
Returns the current count from the counter if enabled. If reset, | |
this is the value before the reset. | |
>>> import u3 | |
>>> d = u3.U3() | |
>>> d.debug = True | |
>>> d.configIO(EnableCounter1 = True, FIOAnalog = 15) | |
Sent: [0x63, 0xf8, 0x3, 0xb, 0x5c, 0x0, 0x5, 0x0, 0x48, 0x0, 0xf, 0x0] | |
Response: [0x5e, 0xf8, 0x3, 0xb, 0x57, 0x0, 0x0, 0x0, 0x48, 0x0, 0xf, 0x0] | |
{'NumberOfTimersEnabled': 0, 'TimerCounterPinOffset': 4, 'DAC1Enable': 0, 'FIOAnalog': 15, 'EIOAnalog': 0, 'TimerCounterConfig': 72, 'EnableCounter1': True, 'EnableCounter0': False} | |
>>> d.getFeedback(u3.Counter1(Reset = False)) | |
Sent: [0x32, 0xf8, 0x2, 0x0, 0x37, 0x0, 0x0, 0x37, 0x0, 0x0] | |
Response: [0xfc, 0xf8, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0] | |
[0] | |
>>> # Tap a ground wire to counter 1 | |
>>> d.getFeedback(u3.Counter1(Reset = False)) | |
Sent: [0x32, 0xf8, 0x2, 0x0, 0x37, 0x0, 0x0, 0x37, 0x0, 0x0] | |
Response: [0xfd, 0xf8, 0x4, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0] | |
[1] | |
>>> # Tap a ground wire to counter 1 | |
>>> d.getFeedback(u3.Counter1(Reset = False)) | |
Sent: [0x32, 0xf8, 0x2, 0x0, 0x37, 0x0, 0x0, 0x37, 0x0, 0x0] | |
Response: [0xb4, 0xf8, 0x4, 0x0, 0xb7, 0x0, 0x0, 0x0, 0x0, 0x6b, 0x2b, 0x21, 0x0, 0x0] | |
[2173803] | |
''' | |
def __init__(self, Reset = False): | |
Counter.__init__(self, 1, Reset) | |
def __repr__(self): | |
return "<u3.Counter0( Reset = %s )>" % self.reset | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Goal is to hack u3 labjack driver into a mock object so labjack code can be tested without labjack present