Permalink
Fetching contributors…
Cannot retrieve contributors at this time
executable file 898 lines (825 sloc) 34.8 KB
% ========================================================================
%> @brief LABJACK Connects and manages a LabJack U3 / U6
%>
%> Connects and manages a LabJack U3 / U6. To run this in OS X and Linux,
%> you need to install libusb and the exodriver. The easiest way to do this
%> is to use homebrew on OS X, a light-weight package manager to install
%> universal builds of these:
%> bash$ brew install libusb exodriver --universal
%> For linux, see instructions on the labjack site.
%> With the exodriver installed, you create a new labJack object and you
%> can then dend figital I/O commands and strobed words. labJack ises a 12bit
%> word across EIO and CIO, using CIO0 as the strobe bit so one has a
%> resultant 11bits of values in the strobed word. For example:
%>
%> >> lj = labJack('verbose',true) %open labJack verbosely
%> >> lj.toggleFIO(1) %toggle FIO1 between low and high
%> >> lj.timedTTL(3,200) % send a 200ms timed TTL pulse on FIO3
% ========================================================================
classdef labJack < handle
properties
%> friendly object name, setting this to 'null' will force silentMode=1
name='LabJack'
%> what LabJack device to use; 3 = U3, 6 = U6
deviceID = 6
%> if more than one labJack connected, which one to open?
device = 1
%> silentMode allows one to gracefully fail methods without a labJack connected
silentMode = false
%> header needed by loadlib
header = '/usr/local/include/labjackusb.h'
%> the library itself
library = '/usr/local/lib/liblabjackusb'
%> how long to wait to read or write to the LabJack in
%> milliseconds, 0 = infinity
timeOut = 0
%> do we log everything to the command window?
verbose = false
%> allows the constructor to run the open method immediately (default)
openNow = true
%> whether we read the response (true) or not (false) to commands we send.
%> The LabJack usually requires that we read the response and do a
%> soft reset if no response is read, but it does allow us to not
%> have to wait till we get a response, thus can speed methods like
%> timedTTL up.
readResponse = true
%> strobeTime is time of strobe in unit multiples of timeShort: 16
%> units ~=1ms on a U6 where timeShort is 64e-6 .If you use a U3
%> this needs to be 8 for a 1ms pulse...
strobeTime = 16
end
properties (SetAccess = private, GetAccess = public)
%> function list returned from loading the exodriver
functionList
%> library version returned on first open
version
%> how many devices are connected
devCount
%> handle to the opened device itself
handle = []
%> have we successfully opened the labjack?
isOpen = false
%> an input buffer
inp = []
%> output buffer, normally the number of bytes written
outp = []
%> FIO0 state
fio0 = 0
%> FIO1 state
fio1 = 0
%> FIO2 state
fio2 = 0
%> FIO2 state
fio3 = 0
%> FIO4 state
fio4 = 0
%> FIO5 state
fio5 = 0
%> FIO6 state
fio6 = 0
%> FIO7 state
fio7 = 0
%> LED state, which is controllable only on the U3
led = 1
%> The raw strobed word command generated with prepareStrobe, sent with strobeWord
command = []
%> universal ID
uuid = 0
%> clock() dateStamp set on construction
dateStamp = []
end
properties (SetAccess = private, Dependent = true)
%> The fullName is the object name combined with its uuid and class name
fullName = ''
end
properties (SetAccess = private, GetAccess = private)
% WaitShort time quantum is 64microseconds for U6 and 128microseconds for U3
timeShort = 64e-6
% WaitLong time quantum is 16ms for U6 and 32ms for U3
timeLong = 16e-3
%>raw commands ,you can use labjackPython to find/verify these. These
%>are easy ways to control the I/O, but this object also includes
%>SetDIO which calculates the command denovo and can control CIO EIO
%>and FIO. The raw commands below may be faster, but I've never been
%>able to tell a difference when benchmarking them.
fio0High = hex2dec(['15'; 'f8'; '03'; '00'; '18'; '01'; '00'; '0d'; '80'; '0b'; '80'; '00'])'
fio1High = hex2dec(['17'; 'f8'; '03'; '00'; '1a'; '01'; '00'; '0d'; '81'; '0b'; '81'; '00'])'
fio2High = hex2dec(['19'; 'f8'; '03'; '00'; '1c'; '01'; '00'; '0d'; '82'; '0b'; '82'; '00'])'
fio3High = hex2dec(['1b'; 'f8'; '03'; '00'; '1e'; '01'; '00'; '0d'; '83'; '0b'; '83'; '00'])'
fio4High = hex2dec(['1d'; 'f8'; '03'; '00'; '20'; '01'; '00'; '0d'; '84'; '0b'; '84'; '00'])'
fio5High = hex2dec(['1f'; 'f8'; '03'; '00'; '22'; '01'; '00'; '0d'; '85'; '0b'; '85'; '00'])'
fio6High = hex2dec(['21'; 'f8'; '03'; '00'; '24'; '01'; '00'; '0d'; '86'; '0b'; '86'; '00'])'
fio7High = hex2dec(['23'; 'f8'; '03'; '00'; '26'; '01'; '00'; '0d'; '87'; '0b'; '87'; '00'])'
fio0Low = hex2dec(['94'; 'f8'; '03'; '00'; '98'; '00'; '00'; '0d'; '80'; '0b'; '00'; '00'])'
fio1Low = hex2dec(['96'; 'f8'; '03'; '00'; '9a'; '00'; '00'; '0d'; '81'; '0b'; '01'; '00'])'
fio2Low = hex2dec(['98'; 'f8'; '03'; '00'; '9c'; '00'; '00'; '0d'; '82'; '0b'; '02'; '00'])'
fio3Low = hex2dec(['9a'; 'f8'; '03'; '00'; '9e'; '00'; '00'; '0d'; '83'; '0b'; '03'; '00'])'
fio4Low = hex2dec(['9c'; 'f8'; '03'; '00'; 'a0'; '00'; '00'; '0d'; '84'; '0b'; '04'; '00'])'
fio5Low = hex2dec(['9e'; 'f8'; '03'; '00'; 'a2'; '00'; '00'; '0d'; '85'; '0b'; '05'; '00'])'
fio6Low = hex2dec(['a0'; 'f8'; '03'; '00'; 'a4'; '00'; '00'; '0d'; '86'; '0b'; '06'; '00'])'
fio7Low = hex2dec(['a2'; 'f8'; '03'; '00'; 'a6'; '00'; '00'; '0d'; '87'; '0b'; '07'; '00'])'
ledIsON = hex2dec(['05'; 'f8'; '02'; '00'; '0a'; '00'; '00'; '09'; '01'; '00'])' %only works on U3
ledIsOFF = hex2dec(['04'; 'f8'; '02'; '00'; '09'; '00'; '00'; '09'; '00'; '00'])' %only works on U3
%> Is our handle a valid one, this is a cache so we save a bit of
%> time on calling the method each time
vHandle = 0
%> what properties are allowed to be passed on construction
allowedProperties='timeOut|device|readResponse|deviceID|name|silentMode|verbose|openNow|header|library|strobeTime'
%>document what our strobed word is actually setting, shown to user if verbose = true
strobeComment = ''
%> class name
className = ''
%> timedTTL cache
timedTTLCache = []
end
%=======================================================================
methods %------------------PUBLIC METHODS
%=======================================================================
% ===================================================================
%> @brief Class constructor
%>
%> We use parseArgs to parse allowed properties on construction and also
%> switch into silent mode and/or auto open the labjack connection.
%>
%> @param varargin are passed as a structure of properties which is
%> parsed.
%> @return instance of labJack class.
% ===================================================================
function obj = labJack(varargin)
obj.className = class(obj);
obj.dateStamp = clock();
obj.uuid = num2str(dec2hex(floor((now - floor(now))*1e10)));
if nargin>0
obj.parseArgs(varargin,obj.allowedProperties);
end
if strcmpi(obj.name, 'null') || ispc %we were deliberately passed null, means go into silent mode
obj.silentMode = true;
obj.verbose = true;
obj.salutation('CONSTRUCTOR Method','labJack running in silent mode...')
obj.verbose = false;
elseif obj.openNow == true
obj.open
end
end
% ===================================================================
%> @brief Open the LabJack device
%>
%> Open the LabJack device
% ===================================================================
function open(obj)
if obj.silentMode == false || isempty(obj.handle)
if ismac == true || isunix == true
if ~libisloaded('liblabjackusb')
try
loadlibrary(obj.library,obj.header);
catch ME
obj.salutation('open method',['Loading the exodriver library failed: ' ME.message]);
obj.version = ['Library Load FAILED: ' ME.message];
obj.silentMode = true;
obj.verbose = true;
return
end
end
obj.functionList = libfunctions('liblabjackusb', '-full'); %store our raw lib functions
obj.version = calllib('liblabjackusb','LJUSB_GetLibraryVersion');
obj.devCount = calllib('liblabjackusb','LJUSB_GetDevCount',obj.deviceID);
else %incomplete PC support, basically need to add PC equivalents of rawRead and rawWrite
obj.library = 'labjackud';
obj.header = 'C:\progra~1\LabJack\drivers\labjackud.h';
if (libisloaded('labjackud') || (libisloaded('labjackud_doublePtr')))
% Libraries already loaded
else
loadlibrary(obj.library,obj.header);
loadlibrary labjackud labjackud_doublePtr.h alias labjackud_doublePtr
% If you wish to view a list of the available LabJack UD functions
% and their associated Output Values and Input Arguments, uncomment out
% the appropriate line of code below.
%libfunctionsview labjackud % Use this in version 7.0 and newer
%libfunctionsview labjackud_doublePtr % Use this in version 7.0+
%libmethodsview labjackud % Use this in version 6.5
%libmethodsview labjackud_doublePtr % Use this in version 6.5
end
end
obj.inp=zeros(10,1);
if obj.devCount == 0 %no device was found with input deviceID, lets scan for another device
if obj.deviceID == 3 %we tried a U3, now lets try a U6
obj.devCount = calllib('liblabjackusb','LJUSB_GetDevCount',6);
if obj.devCount > 0 %yup it's a U6
obj.deviceID = 6;
end
elseif obj.deviceID == 6 %we tried a U6, now lets try a U3
obj.devCount = calllib('liblabjackusb','LJUSB_GetDevCount',3);
if obj.devCount > 0
obj.deviceID = 3;
end
end
if obj.devCount == 0
obj.salutation('open method','No LabJack U3 or U6 devices found, going into silent mode');
obj.version = 'device discovery FAILED';
obj.isOpen = false;
obj.handle = [];
obj.vHandle = false;
obj.verbose = false;
obj.silentMode = true; %we switch into silent mode just in case someone tries to use the object
return
end
end
obj.handle = calllib('liblabjackusb','LJUSB_OpenDevice',obj.device,0,obj.deviceID);
if obj.validHandle()
obj.version = calllib('liblabjackusb','LJUSB_GetDeviceDescriptorReleaseNumber',obj.handle);
if obj.deviceID == 3 %respecify the time quantum for the U3
obj.timeShort = 128e-6;
obj.timeLong = 32e-3;
end
obj.isOpen = true;
obj.salutation('open method','LabJack succesfully opened...');
obj.salutation('open method',sprintf('Device U%g - Time Quantum short/long = %g secs / %g secs',obj.deviceID,obj.timeShort,obj.timeLong));
none=[0,0,0];
obj.setDIO(none); %Sink all our DIO to output LOW
else
obj.salutation('open method','LabJack failed to open, going into silent mode');
obj.version = 'device opening FAILED';
obj.isOpen = false;
obj.handle = [];
obj.verbose = false;
obj.silentMode = true; %we switch into silent mode just in case someone tries to use the object
end
else %silentmode is ~false
obj.close();
obj.isOpen = false;
obj.handle = [];
obj.vHandle = false;
obj.verbose = false;
obj.silentMode = true; %double make sure it is set to true
end
end
% ===================================================================
%> @brief Close the LabJack device
%> void LJUSB_CloseDevice(HANDLE hDevice);
%> //Closes the handle of a LabJack USB device.
% ===================================================================
function close(obj)
if ~isempty(obj.handle)
if obj.validHandle() == true %double-check we still have valid handle
calllib('liblabjackusb','LJUSB_CloseDevice',obj.handle);
end
obj.salutation('CLOSE method','LabJack Handle has been closed');
obj.isOpen = false;
obj.handle=[];
obj.vHandle = false;
else
obj.salutation('CLOSE method','No handle to close...');
end
end
% ===================================================================
%> @brief Is Handle Valid?
%> bool LJUSB_IsHandleValid(HANDLE hDevice);
%> //Is handle valid.
% ===================================================================
function vHandle = validHandle(obj)
obj.vHandle = false; %our cached value
if obj.silentMode == false
if ~isempty(obj.handle)
obj.vHandle = calllib('liblabjackusb','LJUSB_IsHandleValid',obj.handle);
if obj.vHandle
obj.salutation('validHandle Method',sprintf('Handle to LabJack U%g is VALID',obj.deviceID));
else
obj.salutation('validHandle Method',sprintf('Handle to LabJack U%g is INVALID',obj.deviceID),true);
end
else
obj.vHandle = false;
obj.isOpen = false;
obj.handle = [];
obj.salutation('validHandle Method','Handle to LabJack is INVALID (empty handle)',true);
end
end
vHandle = obj.vHandle;
end
% ===================================================================
%> @brief Write formatted command string to LabJack
%> unsigned long LJUSB_Write(HANDLE hDevice, BYTE *pBuff, unsigned long count);
%> // Writes to a device. Returns the number of bytes written, or -1 on error.
%> // hDevice = The handle for your device
%> // pBuff = The buffer to be written to the device.
%> // count = The number of bytes to write.
%> // This function replaces the deprecated LJUSB_BulkWrite, which required the endpoint
%>
%> @param byte The raw hex encoded command packet to send
% ===================================================================
function out = rawWrite(obj,byte)
out = calllib('liblabjackusb', 'LJUSB_WriteTO', obj.handle, byte, length(byte), obj.timeOut);
if out == 0; obj.salutation('rawWrite','ERROR WRITING!',true); end
end
% ===================================================================
%> @brief Read response string back from LabJack
%> unsigned long LJUSB_Read(HANDLE hDevice, BYTE *pBuff, unsigned long count);
%> // Reads from a device. Returns the number of bytes read, or -1 on error.
%> // hDevice = The handle for your device
%> // pBuff = The buffer to filled in with bytes from the device.
%> // count = The number of bytes expected to be read.
%> // This function replaces the deprecated LJUSB_BulkRead, which required the endpoint
%>
%> @param bytein
%> @param count
% ===================================================================
function in = rawRead(obj,bytein,count)
if ~exist('bytein','var')
bytein = zeros(10,1);
end
if ~exist('count','var') || count > length(bytein)
count = length(bytein);
end
in = calllib('liblabjackusb', 'LJUSB_ReadTO', obj.handle, bytein, count, obj.timeOut);
if in == 0; obj.salutation('rawRead','ERROR READING!',true); end
end
% ===================================================================
%> @brief WaitShort
%> LabJack Wait in multiples of 64/128microseconds
%> @param time time in ms; remember 64/128microseconds is the atomic minimum
% ===================================================================
function waitShort(obj,time)
if obj.silentMode == false && obj.vHandle == 1
time = time / 1000; %convert to seconds
time=ceil(time/obj.timeLong);
if time > 255
time = 255; %truncate to maximum time delay allowed
end
cmd=zeros(10,1);
cmd(2) = 248; %hex2dec('f8'); %feedback
cmd(3) = 2; %number of bytes in packet
cmd(8) = 5; %IOType for waitshort is 5
cmd(9) = time;
obj.command = obj.checksum(cmd,'extended');
obj.outp = obj.rawWrite(obj.command);
if obj.readResponse; obj.inp = obj.rawRead(zeros(1,10),10); end
end
end
% ===================================================================
%> @brief WaitLong
%> LabJack Wait in multiples of 16/32ms
%> @param time time in ms, remember 16/32ms is the atomic minimum
% ===================================================================
function waitLong(obj,time)
if obj.silentMode == false && obj.vHandle == 1
time = time / 1000; %convert to seconds
time=ceil(time/obj.timeLong);
if time > 255
time = 255; %truncate to maximum time delay allowed
end
cmd=zeros(10,1);
cmd(2) = 248; %hex2dec('f8'); %feedback
cmd(3) = 2; %number of bytes in packet
cmd(8) = 6; %IOType for waitlong is 6
cmd(9) = time;
obj.command = obj.checksum(cmd,'extended');
obj.outp = obj.rawWrite(obj.command);
if obj.readResponse; obj.inp = obj.rawRead(zeros(1,10),10); end
end
end
% ===================================================================
%> @brief timedTTL Send a TTL with a defined time of pulse
%>
%> Note that there is a maximum time to the TTL pulse which is ~8.16secs
%> for the U3 and ~4.08secs for the U6; we can extend that time by
%> adding more feedback commands in the command packet but this
%> shouldn't be needed anyway. Any time longer than this will be
%> truncated to the maximum allowable time.
%>
%> @param line 0-7=FIO, 8-15=EIO, or 16-19=CIO
%> @param time time in ms
%> @param sync optional logical flag whether to use blocking (true) command
% ===================================================================
function timedTTL(obj,line,time)
if (~exist('line','var') || ~exist('time','var'))
if ~isempty(obj.timedTTLCache)
obj.outp = obj.rawWrite(obj.timedTTLCache);
if obj.readResponse; obj.inp = obj.rawRead(zeros(1,10),10); end
obj.salutation('timedTTL method','Cached Command used')
else
fprintf('\ntimedTTL Input options: \n\tline (single value 0-7=FIO, 8-15=EIO, or 16-19=CIO), time (in ms)\n\n');
end
return
end
if obj.silentMode == false && obj.vHandle == 1
time = time / 1000; %convert to seconds
time1 = 0;
time2 = 0;
if time >= obj.timeLong %we need to use greater resolution for fine timing
time1 = floor(time/obj.timeLong);
if time1 > 255 %truncate to maximum time delay allowed
time1 = 255; %truncate to maximum time delay allowed
elseif time1 < 1 %truncate to minimum
time1 = 1;
end
time2 = time - (time1 * obj.timeLong);
time2 = round(time2/obj.timeShort);
if time2 > 255 %truncate to maximum time delay allowed
time2 = 255; %truncate to maximum time delay allowed
elseif time2 < 0 %truncate to minimum
time2 = 0;
end
otime = (time1 * obj.timeLong) + (time2 * obj.timeShort);
cmd=zeros(16,1);
cmd(2) = 248; %command byte for feedback command (f8 in hex)
cmd(3) = (length(cmd)-6)/2;
cmd(8) = 11; %BitStateWrite: IOType=11
cmd(9) = line+128; %add 128 as bit 7 sets value high
cmd(10) = 6; %IOType for waitshort is 5, waitlong is 6
cmd(11) = time1; %time to wait in unit multiples
cmd(12) = 5; %IOType for waitshort is 5, waitlong is 6
cmd(13) = time2; %time to wait in unit multiples
cmd(14) = 11; %BitStateWrite: IOType=11
cmd(15) = line; %bit to set low
else
time2=ceil(time/obj.timeShort);
if time2 > 255 %truncate to maximum time delay allowed
time2 = 255; %truncate to maximum time delay allowed
end
iotype = 5;
otime = time2 * obj.timeShort;
cmd=zeros(14,1);
cmd(2) = 248; %command byte for feedback command (f8 in hex)
cmd(3) = (length(cmd)-6)/2;
cmd(8) = 11; %BitStateWrite: IOType=11
cmd(9) = line+128; %add 128 as bit 7 sets value high
cmd(10) = iotype; %IOType for waitshort is 5, waitlong is 6
cmd(11) = time2; %time to wait in unit multiples, this is the time of the strobe
cmd(12) = 11; %BitStateWrite: IOType=11
cmd(13) = line;
end
obj.command = obj.checksum(cmd,'extended');
obj.timedTTLCache = obj.command;
obj.outp = obj.rawWrite(obj.command);
if obj.readResponse; obj.inp = obj.rawRead(zeros(1,10),10); end
obj.salutation('timedTTL method',sprintf('Line:%g Tlong:%g Tshort:%g output time = %g ms', line, time1, time2, otime*1000))
end
end
% ===================================================================
%> @brief setDIO
%> setDIO sets the direction/value for FIO, EIO and CIO
%> If only value supplied, set all others to [255,255,255]
%> @param value is binary identifier for 0-7 bit range
%> @param mask is the mask to apply the command
%> @param valuedir binary identifier for input (0) or output (1) default=[255, 255, 255]
%> @param maskdir is the mask to apply the command. default=[255, 255,255]
% ===================================================================
function setDIO(obj,value,mask,valuedir,maskdir)
if ~exist('value','var');fprintf('\nsetDIO Input options: \n\tvalue, [mask], [value direction], [mask direction]\n\n');return;end
if ~exist('mask','var');mask=[255,255,255];end %all DIO by default
if ~exist('valuedir','var');valuedir=[255,255,255];maskdir=valuedir;end %all DIO set to output
if obj.silentMode == false && obj.vHandle == 1
cmd=zeros(14,1);
cmd(2) = 248; %command byte for feedback command (f8 in hex)
cmd(3) = (length(cmd)-6)/2;
cmd(8) = 29; %IOType for PortDirWrite = 29
cmd(9:11) = maskdir;
cmd(12:14) = valuedir;
cmd(8) = 27; %IOType for PortStateWrite = 27
cmd(9:11) = mask;
cmd(12:14) = value;
obj.command = obj.checksum(cmd,'extended');
obj.outp = obj.rawWrite(obj.command);
if obj.readResponse; obj.inp = obj.rawRead(zeros(1,10),10); end
end
end
% ===================================================================
%> @brief setDIODirection
%> setDIODirection sets the direction for FIO, EIO and CIO as read or write
%> @param value is binary identifier for 0-7 bit range
%> @param mask is the mask to apply the command
% ===================================================================
function setDIODirection(obj,value,mask)
if ~exist('value','var');fprintf('\nsetDIODirection Input options: \n\t\tvalue, [mask]\n\n');return;end
if ~exist('mask','var');mask=[255,255,255];end
if obj.silentMode == false && obj.vHandle == 1
cmd=zeros(14,1);
cmd(2) = 248; %command byte for feedback command (f8 in hex)
cmd(3) = (length(cmd)-6)/2;
cmd(8) = 29; %IOType for PortDirWrite = 29
cmd(9:11) = mask;
cmd(12:14) = value;
obj.command = obj.checksum(cmd,'extended');
obj.outp = obj.rawWrite(obj.command);
if obj.readResponse; obj.inp = obj.rawRead(zeros(1,10),10); end
end
end
% ===================================================================
%> @brief setDIOValue
%> setDIOValue sets the value for FIO, EIO and CIO as HIGH or LOW
%> @param value is binary identifier for 0-7 bit range
%> @param mask is the mask to apply the command
% ===================================================================
function setDIOValue(obj,value,mask)
if ~exist('value','var');fprintf('\nSetDIOValue Input options: \n\t\tvalue, [mask]\n\n');return;end
if ~exist('mask','var');mask=[255,255,255];end
if obj.silentMode == false && obj.vHandle == 1
cmd=zeros(14,1);
cmd(2) = 248; %command byte for feedback command (f8 in hex)
cmd(3) = (length(cmd)-6)/2;
cmd(8) = 27; %IOType for PortStateWrite = 27
cmd(9:11) = mask;
cmd(12:14) = value;
obj.command = obj.checksum(cmd,'extended');
obj.outp = obj.rawWrite(obj.command);
if obj.readResponse; obj.inp = obj.rawRead(zeros(1,10),10); end
end
end
% ===================================================================
%> @brief Prepare Strobe Word
%> Sets the strobe value for EIO (8bits) and CIO (4bits) which are
%> accesible via the DB15 using a single cable. This avoids using FIO, which
%> can therefore be used for addtional control TTLs (FIO0 and FIO1 are used
%> for START/STOP and pause/unpause of the Plexon Omniplex in Opticka for
%> example).
%>
%> @param value The value to be strobed, range is 0-2047 for 11bits
%> In Opticka, 0 and 2047 are reserved. Value can be 3 byte markers for
%> FIO (which is ignored), EIO and CIO respectively. CIO0 is used as the
%> strobe line, which leaves EIO0-7 and CIO1-3 for value data.
%> @param mask Which bits to mask
%> @param sendNow if true then sends the value immediately
% ===================================================================
function prepareStrobe(obj,value,mask,sendNow)
if obj.silentMode == false && obj.vHandle == 1
if value>2047;value=2047;end %block anything bigger than 2^11
if value<0; value = 0; end %block anything smaller than 0
obj.strobeComment = ['Original Value = ' num2str(value) ' | '];
[eio,cio]=obj.prepareWords(value,0); %construct our word split to eio and cio, set strobe low
ovalue(1) = 0; %fio will be 0
ovalue(2) = eio;
ovalue(3) = cio;
[eio2,cio2]=obj.prepareWords(value,1); %construct our word split to eio and cio, set strobe high
ovalue2(1) = 0; %fio will be 0
ovalue2(2) = eio2;
ovalue2(3) = cio2;
mask = [0,255,255]; %lock fio, allow all of eio and cio
obj.strobeComment = [obj.strobeComment 'FIO EIO & CIO: ' num2str(0) ' ' num2str(eio2) ' ' num2str(cio2)];
cmd=zeros(30,1);
cmd(2) = 248; %command byte for feedback command (f8 in hex)
cmd(3) = (length(cmd)-6)/2;
cmd(8) = 27; %IOType for PortStateWrite (1b in hex)
cmd(9:11) = mask;
cmd(12:14) = ovalue; %This is our strobe number but with strobe line set low, th
cmd(15) = 27; %IOType for PortStateWrite (1b in hex)
cmd(16:18) = mask;
cmd(19:21) = ovalue2; %The same value but now set strobe high, all our values should be readable
cmd(22) = 5; %IOType for waitshort is 5, waitlong is 6
cmd(23) = obj.strobeTime; %time to wait in unit multiples, this is the time of the strobe
cmd(24) = 27; %IOType for PortStateWrite (1b in hex)
cmd(25:27) = mask;
cmd(28:30) = 0;
obj.command = obj.checksum(cmd,'extended');
if exist('sendNow','var')
obj.strobeWord;
end
end
end
% ===================================================================
%> @brief Send the Strobe command
%>
%>
% ===================================================================
function strobeWord(obj)
if ~isempty(obj.command)
obj.rawWrite(obj.command);
if obj.readResponse; obj.inp = obj.rawRead(zeros(1,10),10); end
%obj.salutation('strobeWord', obj.strobeComment);
% if obj.inp(6) > 0
% obj.salutation('strobeWord',['Feedback error in IOType ' num2str(obj.inp(7))]);
% end
end
end
% ===================================================================
%> @brief Set FIO to a value
%>
%> Note this uses the pregenerated raw commands, so only works with
%> the FIO bits seen in properties above. Us SetDIO and a mask for a
%> robust way to control any digital I/O
%>
%> @param val The value to be set
%> line which FIO to set
% ===================================================================
function setFIO(obj,val,line)
if ~exist('val','var');fprintf('\nInput options: \n\t\tvalue, [line]\n\n');return;end
if obj.silentMode == false && obj.vHandle == 1
if ~exist('line','var');line=0;end
myname = ['fio' num2str(line)];
cmdHigh = [myname 'High'];
cmdLow = [myname 'Low'];
if ~exist('val','var')
val = abs(obj.(myname)-1);
end
if val == 1
obj.outp = obj.rawWrite(obj.(cmdHigh));
if obj.readResponse; obj.inp = obj.rawRead(zeros(1,10),10); end
obj.(myname) = 1;
obj.salutation('SETFIO',[myname ' is HIGH'])
else
obj.outp = obj.rawWrite(obj.(cmdLow));
if obj.readResponse; obj.inp = obj.rawRead(zeros(1,10),10); end
obj.(myname) = 0;
obj.salutation('SETFIO',[myname ' is LOW'])
end
end
end
% ===================================================================
%> @brief Toggle FIO value
%>
%> Note this uses the pregenerated raw commands, so only works with
%> the FIO bits seen in properties above. Us SetDIO and a mask for a
%> robust way to control any digital I/O
%>
% ===================================================================
function toggleFIO(obj,line)
if obj.silentMode == false && obj.vHandle == 1
if ~exist('line','var');line=0;end
myname = ['fio' num2str(line)];
obj.(myname)=abs(obj.(myname)-1);
obj.setFIO(obj.(myname),line);
end
end
% ===================================================================
%> @brief Turn LED ON
%>
%> I think this only works on the U3
% ===================================================================
function ledON(obj)
if obj.silentMode == false && obj.vHandle == 1
obj.outp = obj.rawWrite(obj.ledIsON);
if obj.readResponse; obj.inp = obj.rawRead(zeros(1,10),10); end
end
end
% ===================================================================
%> @brief Turn LED OFF
%>
%> I think this only works on the U3
% ===================================================================
function ledOFF(obj)
if obj.silentMode == false && obj.vHandle == 1
obj.outp = obj.rawWrite(obj.ledIsOFF);
if obj.readResponse; obj.inp = obj.rawRead(zeros(1,10),10); end
end
end
% ===================================================================
%> @brief Reset the LabJack
%>
%> @param resetType whether to use a soft (1) or hard (2) reset
%> type
% ===================================================================
function reset(obj,resetType)
if ~exist('resetType','var')
resetType = 0;
end
cmd=zeros(4,1);
cmd(2) = hex2dec('99'); %command code
if resetType == 0 %soft reset
cmd(3) = bin2dec('01');
else
cmd(3) = bin2dec('10');
end
obj.command = obj.checksum(cmd,'normal');
obj.outp = obj.rawWrite(cmd);
if obj.readResponse; obj.inp = obj.rawRead(zeros(4,1)); end
end
% ===================================================================
%> @brief checksum
%> Calculate checksum for data packet. Note see the labjack
%> documentation; there are 2 types of checksums, normal and extended.
%> This method uses 2 static methods checksum8 and checksum16 for each
%> type respectively.
%>
%> @param command The command that needs checksumming
%> @param type normal | extended
% ===================================================================
function command = checksum(obj,command,type)
switch type
case 'normal'
command(1) = obj.checksum8(command(2:end));
case 'extended'
[command(5),command(6)] = obj.checksum16(command(7:end));
command(1) = obj.checksum8(command(2:6));
end
end
% ===================================================================
%> @brief concatenate the name with a uuid at get.
%> @param
%> @return name the concatenated name
% ===================================================================
function name = get.fullName(obj)
if isempty(obj.name)
name = [obj.className '#' obj.uuid];
else
name = [obj.name ' <' obj.className '#' obj.uuid '>'];
end
end
end
%=======================================================================
methods ( Static ) % STATIC METHODS
%=======================================================================
% ===================================================================
%> @brief checksum8
%> Calculate checksum for data packet
%>
% ===================================================================
function chk = checksum8(in)
in = sum(uint16(in));
quo = floor(in/2^8);
remd = rem(in,2^8);
in = quo+remd;
quo = floor(in/2^8);
remd = rem(in,2^8);
chk = quo + remd;
end
% ===================================================================
%> @brief checksum16
%> Calculate checksum (lsb and msb) for extended data packet
%>
% ===================================================================
function [lsb,msb] = checksum16(in)
in = sum(uint16(in));
lsb = bitand(in,255);
msb = bitshift(in,-8);
end
% ===================================================================
%> @brief Prepare Strobe Word split into EIO (8bit) and CIO (3bit). 0-2047
%> %is the max # of variables with 2^11bits.
%>
%> @param value The value to be split into EIO and CIO
%> @return eio is an 8bit word value represented the LSB
%> @return cio is a 4bit value where the 1st bit is 1 for strobe line 22
%> and the rest is the 3bit remainder to combine with eio to make an
%> 11bit strobed word.
% ===================================================================
function [eio,cio] = prepareWords(value,strobeState)
if ~exist('strobeState','var')
strobeState = 1;
end
eio = bitand(value,255); %get eio easily ANDing with 255
msb = bitshift(value,-8); %our msb is bitshifted 8 bits
msb = bitshift(msb,1); %shift it across as cio0 is reserved;
cio = bitor(msb,strobeState); %OR with 1 as cio0 is the strobe trigger and needs to be 1
end
end % END STATIC METHODS
%=======================================================================
methods ( Access = private ) % PRIVATE METHODS
%=======================================================================
% ===================================================================
%> @brief delete is the object Destructor
%> Destructor automatically called when object is cleared
%>
% ===================================================================
function delete(obj)
obj.salutation('DELETE Method','labJack object Cleaning up...')
obj.close;
end
% ===================================================================
%> @brief salutation - log message to command window
%> log message to command window, dependent on verbosity
%>
% ===================================================================
function salutation(obj,in,message,verbose)
if ~exist('verbose','var')
verbose = obj.verbose;
end
if verbose ~= false
if ~exist('in','var')
in = 'General Message';
end
if exist('message','var')
fprintf(['---> labJack: ' message ' | ' in '\n']);
else
fprintf(['---> labJack: ' in '\n']);
end
end
end
% ===================================================================
%> @brief Sets properties from a structure or varargin cell, ignores invalid properties
%>
%> @param args input structure/cell - will automagically handle
%> either type
%> @param allowedProperties a regex of allowed properties to set at
%> runtime
% ===================================================================
function parseArgs(obj, args, allowedProperties)
allowedProperties = ['^(' allowedProperties ')$'];
while iscell(args) && length(args) == 1
args = args{1};
end
if iscell(args)
if mod(length(args),2) == 1 % odd
args = args(1:end-1); %remove last arg
end
odd = logical(mod(1:length(args),2));
even = logical(abs(odd-1));
args = cell2struct(args(even),args(odd),2);
end
fnames = fieldnames(args); %find our argument names
for i=1:length(fnames);
if regexp(fnames{i},allowedProperties) %only set if allowed property
obj.salutation(fnames{i},'Configuring setting in constructor');
obj.(fnames{i})=args.(fnames{i}); %we set up the properies from the arguments as a structure
end
end
end
end
end