diff --git a/.gitignore b/.gitignore index 2e3ca7c..839ff9a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,10 @@ +makefile- +scripts- *~ *.bak *.*- RHEL7-x86_64 -RHEL8-x86_6 +RHEL8-x86_64 SL6-x86_64 windows-x64 felix-cache diff --git a/README b/README index 7957cb1..8767cfd 100644 --- a/README +++ b/README @@ -1,19 +1,49 @@ - ## -------------------------------------------------------------------------- ## makefile ## - make: installs mocha mex file and associated shared object file locally into $OBJ_DIR=${EPICS_HOST_ARCH}/$(MATLAB_VERSION) - make install: installs mocha mex file and associated shared object file into INSTALL_PATH?=$(INSTALL_MOCHA_LIBDIR) where: INSTALL_MOCHA_LIBDIR= $(CAFE_BASE)/mocha/$(MOCHA_VERSION)/lib/${EPICS_HOST_ARCH}/$(MATLAB_VERSION) - make clean: rm $(OBJ_DIR)/*.o $(OBJ_DIR)/*.so $(OBJ_DIR)/*.$(MEXE) ## -------------------------------------------------------------------------- + + +#RHEL8 +module load gcc/10.4.0 +module load matlab/ + +#Before compiling, update version number in macchinettaSwitch.cpp +#Find the following line and change version/date +#plhs[0]=mxCreateString((char *) "mocha-1.20.1 : 7 May 2024"); + +make -f makefile_rel_1.20-gcc-10.4.0 +# installs mex file locally +# RHEL8-x86_64/> + +make -f makefile_rel_1.20-gcc-10.4.0 install +# installs mex file centrally to +/opt/gfa/cafe/mocha/mocha-1.20.1-gcc-10.4.0/lib/RHEL8-x86_64/ + +#Create AIT module instance +cd /opt/psi/Cafe/cafe-matlab +mdkir 2023a-RHEL8-gcc-10.4.0-cafe-1.20.1 +cd 2023a-RHEL8-gcc-10.4.0-cafe-1.20.1 +mkdir libexec +cd libexec +cp /opt/gfa/cafe/mocha/mocha-1.20.1-gcc-10.4.0/lib/RHEL8-x86_64/2023a/* . + + +#Declare new module, e.g., +cd /opt/psi/Cafe/modulefiles/cafe-matlab +cp 2024a +#in new module, +module load matlab/ + +cp .release-2024a .release- \ No newline at end of file diff --git a/RHEL8-x86_64/2023a/macchinettaSwitch.o b/RHEL8-x86_64/2023a/macchinettaSwitch.o index c8f289c..ca9bb97 100644 Binary files a/RHEL8-x86_64/2023a/macchinettaSwitch.o and b/RHEL8-x86_64/2023a/macchinettaSwitch.o differ diff --git a/RHEL8-x86_64/2023a/mocha.mexa64 b/RHEL8-x86_64/2023a/mocha.mexa64 index dae359d..d6c607c 100755 Binary files a/RHEL8-x86_64/2023a/mocha.mexa64 and b/RHEL8-x86_64/2023a/mocha.mexa64 differ diff --git a/macchinettaSwitch.cpp b/macchinettaSwitch.cpp index ef0a8e3..0220d35 100644 --- a/macchinettaSwitch.cpp +++ b/macchinettaSwitch.cpp @@ -501,7 +501,7 @@ void macchinettaFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prh break; case MOCHA_VERSION: - plhs[0]=mxCreateString((char *) "mocha-1.19.2 : 28 September 2023"); + plhs[0]=mxCreateString((char *) "mocha-1.20.1 : 7 May 2024"); break; case SHOW: diff --git a/makefile b/makefile deleted file mode 100644 index b0c5639..0000000 --- a/makefile +++ /dev/null @@ -1,104 +0,0 @@ -# -# Jan Chrin -# Version: July 2019 - Qt5 -# -# makefile to build mocha mex file -# printenv | grep MATLAB to reveal your MATLAB Directory -# -# -# local executables are built in ./${EPICS_HOST_ARCH}/$(MVER) -# where the MATLAB version is grepped from $(MATLAB) - -MATLAB_ROOT=${MATLAB} -MATLAB_VERSION=$(notdir $(MATLAB_ROOT)) - -##### CHANGE AS APPROPRIATE ################# -#Mocha Version to install -MOCHA_VERSION=mocha-1.16.1-gcc-7.3.0 -#CAFE version to link to -CAFE_VERSION=cafe-1.16.1-gcc-7.3.0 - -EPICS_BASE=${EPICS}/base-7.0.6 -#CAFE project base -CAFE_BASE=/opt/gfa/cafe -CAFE_MOCHA_BASE=${CAFE_BASE}/mocha -CAFE_CPP_BASE=$(CAFE_BASE)/cpp/$(CAFE_VERSION) -BOOST_BASE=${CAFE_BASE}/boost/boost_1_61_0/include - -CAFE_OBJS_DIR = $(CAFE_BASE)/cpp/$(CAFE_VERSION)/lib/$(EPICS_HOST_ARCH)/libcafe.a - -#if qt5 has libQt5Core.so link -#QT5_DIR= /opt/psi/Cafe/cafe-matlab/${MATLAB_VERSION}/libexec -QT5_DIR= ${MATLAB_ROOT}/bin/glnxa64 - -INSTALL_MOCHA_LIBDIR= $(CAFE_MOCHA_BASE)/$(MOCHA_VERSION)/lib/$(EPICS_HOST_ARCH)/$(MATLAB_VERSION) -############################################# - - -#First deteremine if we are on a 32/64 bit machine -#as mex file extensions are named differently -pattern64=x86_64 -pattern32=i386 - -PWD=$(shell pwd) - #hardware platform - HW=$(shell uname -i) - ifeq ($(pattern64),$(findstring $(pattern64), $(HW))) - MEXE=mexa64 - MATLAB_LIB = $(MATLAB_ROOT)/bin/glnxa64 - else - ifeq ($(pattern32),$(findstring $(pattern32), $(HW))) - MEXE=mexglx - MATLAB_LIB = $(MATLAB_ROOT)/bin/glnxa86 - endif - endif - -INSTALL_PATH?=$(INSTALL_MOCHA_LIBDIR) -OBJ_DIR= ${EPICS_HOST_ARCH}/$(MATLAB_VERSION) - -INCLUDEPATH_MOCHA += -I$(MATLAB_ROOT)/extern/include \ - -I$(CAFE_CPP_BASE)/include -I./ \ - -I$(EPICS_BASE)/include -I$(EPICS_BASE)/include/os/Linux \ - -I$(EPICS_BASE)/include/compiler/gcc - -INCLUDEPATH_MACHINETTA += $(INCLUDEPATH_MOCHA) -I$(BOOST_BASE) -I$(BOOST_BASE)/boost - - -# linkage to qt5 required if cafe built with Qt5 -#-lboost_system -lboost_thread-mt -LIBS += -ldl -lca -lCom -lmx -lmex -lmat -lQt5Core -lQt5Xml -#LIBS += -lmx -lmex -lmat - -$(OBJ_DIR)/mocha.$(MEXE): mocha.cpp $(OBJ_DIR)/macchinettaSwitch.o - mex CXXFLAGS='$(CXXFLAGS) -v -largeArrayDims -ansi -fexceptions -fPIC -fno-omit-frame-pointer -pthread -std=c++1z' \ - 'LDFLAGS=-L$(EPICS_BASE)/lib/${EPICS_HOST_ARCH} -Wl,-rpath,$(EPICS_BASE)/lib/${EPICS_HOST_ARCH} -L${QT5_DIR} -Wl,-rpath,${QT5_DIR} -L$(MATLAB_LIB) -Wl,-rpath,$(MATLAB_LIB) $(LIBS)' \ - mocha.cpp $(OBJ_DIR)/macchinettaSwitch.o $(CAFE_OBJS_DIR) \ - -outdir $(OBJ_DIR) -output mocha.$(MEXE) \ - $(INCLUDEPATH_MOCHA) - - - -$(OBJ_DIR)/macchinettaSwitch.o: macchinettaSwitch.cpp macchinettaHelper.h \ - macchinetta.h containerMochaccino.h - mex CXXFLAGS='-v -largeArrayDims -ansi -fexceptions -fPIC -fno-omit-frame-pointer -pthread -std=c++1z' \ - -c macchinettaSwitch.cpp $(INCLUDEPATH_MACHINETTA) 'LDFLAGS=-L$(EPICS_BASE)/lib/${EPICS_HOST_ARCH} -Wl,-rpath,$(EPICS_BASE)/lib/${EPICS_HOST_ARCH} -L$(MATLAB_LIB) -Wl,-rpath,$(MATLAB_LIB) $(LIBS)' -outdir $(OBJ_DIR) - -install: $(OBJ_DIR)/mocha.$(MEXE) - mkdir -p $(INSTALL_PATH) - mex CXXFLAGS='-v -largeArrayDims -ansi -fexceptions -fPIC -fno-omit-frame-pointer -pthread -std=c++1z' \ - mocha.cpp $(OBJ_DIR)/macchinettaSwitch.o $(CAFE_OBJS_DIR) -outdir $(INSTALL_PATH) -output mocha.$(MEXE) $(INCLUDEPATH_MOCHA) \ - 'LDFLAGS=-L$(EPICS_BASE)/lib/${EPICS_HOST_ARCH} -Wl,-rpath,$(EPICS_BASE)/lib/${EPICS_HOST_ARCH} -L$(MATLAB_LIB) -Wl,-rpath,$(MATLAB_LIB) $(LIBS)' - - cp example.m $(INSTALL_PATH) - cp scripts/monitorAction.m $(INSTALL_PATH) - cp scripts/pvtable.m $(INSTALL_PATH) - cp scripts/test.xml $(INSTALL_PATH) - -install_lib: $(OBJ_DIR)/libmacchinetta.so - mkdir -p $(INSTALL_PATH) - cp $(OBJ_DIR)/libmacchinetta.so $(INSTALL_PATH) - -clean: - rm -f $(OBJ_DIR)/*.o $(OBJ_DIR)/*.so $(OBJ_DIR)/*.$(MEXE) - -print-% : ; @echo $* = $($*) diff --git a/scripts/cafe-matlab.sh b/scripts/cafe-matlab.sh index 2571013..aac9d47 100755 --- a/scripts/cafe-matlab.sh +++ b/scripts/cafe-matlab.sh @@ -4,7 +4,7 @@ # This default is ONLY activated # (1) in the absence of the relevant input argument, and # (2) if matlab is not already pre-loaded on your system -MATLAB_DEFAULT=2016b +MATLAB_DEFAULT=2020a # cafe-matlab.sh script to enable use of the mocha mex-file # The script executes the command: module load cafe-matlab/ @@ -15,15 +15,15 @@ MATLAB_DEFAULT=2016b # Usage: cafe-matlab.sh -v -d -s # where the input key value pairs are **optional** # Examples of usage: -# (1) Use mocha with MATLAB version 2016b but do not start matlab [-s false is default] -# cafe-matlab.sh -v 2016b -# (2) Use mocha with MATLAB version 2016b and start matlab -# cafe-matlab.sh -v 2016b -s true +# (1) Use mocha with MATLAB version 2017b but do not start matlab [-s false is default] +# cafe-matlab.sh -v 2017b +# (2) Use mocha with MATLAB version 2020a and start matlab +# cafe-matlab.sh -v 2020a -s true # (3) Use mocha with MATLAB version given by MATLAB_DEFAULT in script # cafe-matlab.sh -v default -s true # cafe-matlab.sh --usedefault [equivalent -v default -s false] # (4) Use mocha with preloaded matlab (else if none, then that given by -d option else MATLAB_DEFAULT ) -# cafe-matlab.sh -d 2016b +# cafe-matlab.sh -d 2020a # cafe-matlab.sh --preloaded [equivalent to -v preloaded -s false] diff --git a/scripts/cagetOld.m b/scripts/cagetOld.m deleted file mode 100755 index efb95e1..0000000 --- a/scripts/cagetOld.m +++ /dev/null @@ -1,118 +0,0 @@ -function value = caget(channel,cached) -% caget('channel') returns current value and additional infos -% of given EPICS channel. -% caget('channel',1) returns last value and additional infos -% of given EPICS channel. -% -% channel can be a channel name or a handle as returned from mcaopen -% -% return value elements: -% val: value (scalar, vector or string) -% sevr: severity as a number -% sevr_str: severity as a string -% stat: status as a number -% stat_str: status as a string -% time: timestamp as a date vector -% units: units string - -persistent severity_str -persistent status_str -persistent zerotime -persistent units - -if ischar(channel) - pv = mocha('open',channel); - - if mocha('isConnected', channel) == false - mocha('openNowAndWait', 0.5) - end - - if mocha('isConnected', channel) == false - error('EPICS channel %s not found', channel); - end -elseif isnumeric(channel) - pv = channel; -else - error ('first argument must be channel name or handle'); -end -if isvector(pv) - pv=pv(1); % truncate -end - -chInfo=mocha ('getChannelInfo',pv); -%dt='native' - -%if (chInfo.dataType=='DBR_ENUM') -% dt='int8' -%end - -if nargin > 1 && cached - pvStruct = mocha('getPVCache',pv); -else - pvStruct = mocha('getPV', pv); -end - - - -pvCtrl = mocha('getCtrlCache',pv); -%pvCtrl - -% initialize severity and status enums -if isempty(severity_str) - severity_str = {'NO_ALARM';'MINOR';'MAJOR';'INVALID'}; - status_str = {'NO_ALARM';'READ';'WRITE';'HIHI';'HIGH';'LOLO';'LOW';'STATE';'COS';'COMM';'TIMEOUT';'HWLIMIT';'CALC';'SCAN';'LINK';'SOFT';'BAD_SUB';'UDF';'DISABLE';'SIMM';'READ_ACCESS';'WRITE_ACCESS'}; -end - - -value.val = pvStruct.val; - -units = pvCtrl.units; -%string = pvCtrl.enumStrings; - -if (pvCtrl.noEnumStrings>0) -%if size(string) > 1 - %disp(size(string)) - value.val_str = value.val; - value.val = mocha('getCache',pv,'int8'); -end - - -%if ~isempty(units{1}) - %value.units = units{1}; -%end -value.units=units; -value.sevr = pvStruct.alarmSeverity; -indx=max(pvStruct.alarmSeverity, 0); -value.sevr_str = severity_str{indx+1}; -value.stat = pvStruct.alarmStatus; -indx=max(pvStruct.alarmStatus, 0); -value.stat_str = status_str{ indx+1}; - - - -timestamp = mocha('getTimestamp',pv); -if (numel(timestamp) == 2) -% old mca version -% do not use mcatime here because 1. it is slow, 2. is returns UTC -% calculating zerotime only once is faster and takes localtime into account -% When daylight saving time begins or ends, restart the program! - if isempty(zerotime) - [status,timezone]=system('date +%z'); % get localtime offset - timeoffs=str2double(timezone); - houroffs=floor(timeoffs/100); - minoffs=(timeoffs-100*houroffs); - zerotime = datenum('1-Jan-1990') + (minoffs/60 + houroffs)/24; - end - time=timestamp(1)+timestamp(2)/1000000000; - if time - time = zerotime+time/24/3600; - end - value.time = datevec(time); -else -% new mca version - timestamp(6)=timestamp(6)+timestamp(7)/1000000000; - value.time = timestamp(1:6); -end - - - diff --git a/scripts/example.m b/scripts/example.m deleted file mode 120000 index 7e0c926..0000000 --- a/scripts/example.m +++ /dev/null @@ -1 +0,0 @@ -../example.m \ No newline at end of file diff --git a/scripts/example.m b/scripts/example.m new file mode 100644 index 0000000..7cece65 --- /dev/null +++ b/scripts/example.m @@ -0,0 +1,1068 @@ +%function example() +%mocha +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Jan Chrin, Paul Scherrer Institut +% March 2017 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% (1) Establishing connections to EPICS Process Variables (PVs) +% (2) Simple single channel operations (and the PVData Object) +% (3) Understanding the Status Error Code / MATLAB Exceptions +% (4) Waveforms and Arrays +% (5) Handling Enumerated Types +% (6) Multiple scalar operations, i.e., operations on several PVs with scalar values +% (7) Multiple cell array ('compound') operations, i.e., on several PVS with scalar/vector values +% (8) Multiple Struct operations on several PVS returning PVData Objects plus Multiple Sets for Scalars/Vectors +% (9) Asynchronous interactions and retrieving data from Cache +% (10) Synchronous group operations, also with externally defined groups +% (11) Monitors, either with or without user supplied callbacks (in essence, matlab scripts) +% (12) Control system parameters, i.e., operating limits, engineerimg units +% (13) Retrieve channel medadata, e.g., data type, native no. elements, connection state, read/write access, etc. +% (14) Setting timeouts for set/get operations +% (15) Setting synchronous group timeouts for set/get operations +% (16) Special Methods, e.g., setAndGet, setAndMatch +% (17:END) Gracefully terminate CAFE +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% the mocha release is accompanied with the long established mca scripts +% which have been accordingly 'mocha-fied', +% i.e., the 'mocha' interface is used from within the mca scripts +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Test channels +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% To run this test script, first create 5 soft channels of the given class. +% pv(1:2) are scalar numerics, pv(3) is a wf, pv(4) is a mbbo record (enum), +% pv(5) is a dbr_string_t, pv(6) does not exist +pv={'ARIDI-BPM-01LE:X-AVG','ARIDI-BPM-01LE:Y-AVG','ARIDI-BPM-01LE:WF-INT-2','ARIDI-BPM-01LE:SET-ENABLE','ARIDI-BPM-01LE:SET-ENABLE.DESC','PV-JOKE'}; + +% +% MATLAB's Run and Advance utility will run each of these 17 sections at the user's prompt. + +% To create an executable: +% uncomment function example in first line and run the mcc compiler +% mcc -m example +% ./run_example.sh $MATLAB_DIR + + +% The following monitorAction.m is included in the movcha release for test purposes. +% Otherwise please copy and place it in your local directory from where matlab +% will be started. This file can optionally be used as a callback function for monitors. + +%monitorAction.m +%{ +function varargout = monitorAction(varargin) +disp('monitorAction called for:'); +pvName=mocha('getPVFromHandle', varargin{1}); +disp(pvName); +X=['Handle =', num2str(varargin{1})]; +disp(X); + +%[varargout{1} varargout{2}] = mocha ('getCache', varargin{1}); +[var1,var2]=mocha ('getCache', varargin{1}); +[s,t]=mocha('getStatus', varargin{1}); +%X=['Value=', num2str(varargout{1}), ' Status=', num2str(s), ' [',t(1), ' ', t(2),']']; +X=['Value =', num2str(var1)]; +Y=['Status=', num2str(s)]; +disp(X) +disp(Y) +disp([t(1),t(2)]) +%} + + + +%%%% +mocha('test'); %test if mocha MEX-file is accessible +mocha('version'); %lists mocha/cafe version +%mocha('show'); %lists all available mocha methods +%%%% + + + +%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% (1) Establishing connections to EPICS Process Variables (PVs) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%Explicitly opening channels is good practice even if only optional +disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'); +disp('Section (1) Establishing connections to EPICS Process Variables (PVs) '); +disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'); + +%returns an array of handles (object references) +%hpv=mocha('open',pv); + +%When executing the 'open' message as above, the default behaviour +%is for each 'open' to wait for a maximum amount of time, given by: +openTime = mocha ('getOpenWaitTime'); %currently 0.4s +%The 'open' wait time can, however, be configured by the user as follows: +mocha ('setOpenWaitTime', 0.2); %set to 0.2s +mocha ('setOpenWaitTime'); %reset to default (0.4s) +%The above shoud be set before the mocha 'open' method is executed + + +%If opening numerous channels, however, better to do this with a single message. +%This is done as shown here: +mocha('openPrepare'); +hpv=mocha('open',pv); +% and more mocha 'open' messages would follow here... +% Finally send the messages and wait for a maximum of 0.2s for connections to complete +mocha('openNowAndWait', 0.2) + +%There are a number of ways to extract information on the created handles +%print all handles whether connected or not +mocha('printHandles'); + +%Array of handles and matching PVnames +[handles, pvs] = mocha ('getHandles'); +[handles, pvs] = mocha ('getConnectedHandles'); +[handles, pvs] = mocha ('getDisconnectedHandles'); +%Array of handles, matching PVnames and connection states +[handles, pvs, states] = mocha ('getHandleStates'); + +%print information on disconnected channels +if (~mocha('allConnected')) + mocha('printDisconnectedHandles'); + %or + [handles, pvs] = mocha ('getDisconnectedHandles'); + for n =1 : length(handles) + X=['Handle=', num2str(handles(n)), 'PV=',pvs(n)]; + disp(X); + end +end + +%To check on the connection state of a single channel +logicValue=mocha('isConnected', pv(1)); %by pvName +logicValue=mocha('isConnected', hpv(1)); %byHandle + + +%Handle and PV Mapping +%Retrieve handle for a given PV +handle = mocha ('getHandleFromPV', pv(1)); +pvName = mocha ('getPVFromHandle', hpv(1)); + +%% +%or run the MATLAB script (which also shows latest values) +disp('If val is NaN then a harmless warning will appear from struct2table'); +%Warning: Out of range or non-integer values truncated during +%conversion to character + +pvtable + + +%Channels may be closed when the application no longer needs them +%mocha ('close', pv(1)); %close given channel +%mocha ('close', pv); %close given channels +%Close all chanels and release all ca resources before exiting MATLAN +%mocha ('close'); + +%END (1) Establishing connections to EPICS Process Variables (PVs) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%(2) Simple single channel operations (and the PVData Object) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'); +disp('Section (2) Simple single channel operations '); +disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'); +%Now perform some get/set operations + +%Mocha operations will accept either a pv name or the pv handle +%(as returned from the mocha 'open' method) as the 2nd input argument + +%GET value +%by pvName; value (scalar or vector) returned in native data type +[value, status]= mocha ('get', pv(1)); +%by Handle; value (scalar or vector) returned in native data type +[value, status]= mocha ('get', hpv(1)); + +%by pvName; value (scalar or vector) returned as a MATLAB double +[value, status]= mocha ('get', pv(1), 'uint8'); +%by pvName; value (scalar or vector) returned as a MATLAB uint8 type +[value, status]= mocha ('get', pv(1), 'double'); + +%SET +%value (scalar or vector) can be in any MATLAB data type +[status] = mocha('set', pv(1), value); + +%Single channel operations that return data, alarms and timestamps +%pvData struct returned; pvData.val has the native data type +pvData = mocha ('getPV', pv(1)); +%pvData struct returned; pvData.val has the double data type +disp('Displaying pvdata struct'); +pvData = mocha ('getPV', pv(1), 'double') + +pvData.val; +pvData.status; % int32 +pvData.alarmStatus; %int16 +pvData.alarmSeverity; %int16 +pvData.ts; %[year, month, day, hour, min, sec, nsec] + + +%Other ways to retrieve alarms and timestamps from cache following a 'get' + ts=mocha('getTimestamp', pv(1)); +[ets]=mocha('getETS', pv(1)) % [secPastEpoch, nsec] + +[alarmStatSev] = mocha ('getAlarm', pv(1)); %[alarmStatus, alarmSeverity] +[alarmStatSev] = mocha ('getAlarmAsString', pv(1)) %[alarmStatus, alarmSeverity] + +%The string equivalenty of an integer alarmStatus/Severity +%may be gotten at any time as follows; +alarmStatus_str = mocha('alarmStatusAsString', pvData.alarmStatus); +alarmSeverity_str = mocha('alarmSeverityAsString', pvData.alarmSeverity); + +%Alarm conditions and alarm severities can be listed as follows: +disp('Listing all possible alarm condition value/name pairs') +[strVal, intVal] = mocha('alarmStatusList'); +for n = 1:length(intVal) + [intVal(n), strVal(n)] +end +disp('Listing all possible alarm severity value/name pairs') +[strVal, intVal] = mocha('alarmSeverityList'); +for n = 1:length(intVal) + [intVal(n), strVal(n)] +end + + +%An extended (x) struct holding supplementary data may also be retrieved: +disp('Displaying extended pvdata struct'); +pvStruct = mocha ('getStruct', pv(1)) +pvStruct.handle; %uint32 +pvStruct.pv; %char +pvStruct.val; +pvStruct.status; %int32 +pvStruct.status_str; %char +pvStruct.alarmStatus; %int16 +pvStruct.alarmStatus_str; %char +pvStruct.alarmSeverity; %int16 +pvStruct.alarmSeverity_str; %char +pvStruct.ts; %[year, month, day, hour, min, sec, nsec] +pvStruct.epicsTS; %[secPastEpoch, nsec] + +%END (2) Simple single channel operations +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%(3) Understanding the Status Error Code / MATLAB Exceptions +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'); +disp('Section (3) Understanding the Status Error Code / MATLAB Exceptions'); +disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'); +[value, status]= mocha ('get', pv(1)); + pvData = mocha ('getPV', pv(1)); + status = pvData.status; + +%A Status Code of 1 represents a normal completion +%Status Codes <=480 are generated by the native ca library +%Status Codes >=600 are generated by the underlying CAFE library + +%A status code is paired to an enumerated name +statusAsString=mocha ('statusAsString', status); +%The following returns the enumerated name +%preceded with severity (SUCCESS, INFO, WARNING, ERROR) +statusText = mocha ('statusAsText', status); +%Further information concerning the code +statusInfo = mocha ('statusInfo', status); + +%Another way to retrieve the full status information w.r.t. the previous +%operation on a given handle is +[status, statusArray] = mocha ('getStatus', pv(1)) +%status is the integer status code +%statusArray[1] returns same data as statusText above +%statusArray[2] returns same data as statusInfo above + +%Status code/name pairs can be listed as follows: +disp('Listing all possible status code value/name pairs') +[strVal, intVal] = mocha('statusList'); + +%Alarm conditions and alarm severities can be listed as follows: +%disp('Listing all possible alarm condition value/name pairs') +[strVal, intVal] = mocha('alarmStatusList'); +for n = 1:length(intVal) + [intVal(n), strVal(n)]; %not printed to window +end + +%Rather than have to check on the status codes, CAFE MATLAB exceptions can be +%enabled (mocha default is to have exceptions dis-enabled) + +mocha ('withExceptions', true) %enables MATLAB exceptions for single channel operations + +try + [val, status] = mocha ('get', pv(6)) %pv(6) is dis-connected as channel does not exist +catch ME + ME + %A MATLAB exception, MException, comprises the 'identifier' and 'message' properties + if strfind(ME.identifier,'CAFE_WARN') + warning(ME.message); + elseif strfind(ME.identifier, 'CAFE_INFO') + disp(ME.message); + elseif strfind(ME.identifer,'CAFE_ERROR') + error(ME.message); + else + disp(ME.message); + end +end + +mocha ('withExceptions', false) %dis-enable MATLAB exceptions for single channel operations + +%END (3) Simple single channel operations +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%(4) Waveforms and Arrays +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'); +disp('Section (4) Waveforms and Arrays'); +disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'); + +[value, status] = mocha ('get', pv(3)); %Returns all elements of the wf +[pvdata] = mocha ('getPV', pv(3)); %Returns all elements of the wf in pvdata.val + +%The default behaviour is for all elements of the wf to be read out and +%presented. However, this number together with an offset can be configured +%by the user + +nelemWF = mocha('setNelem', pv(3), 20); +offsetWF= mocha('setOffset',pv(3), 12); + +%nelemWF = mocha('setNelem', pv(3)); %sets to native value +%offsetWF= mocha('setOffset',pv(3), 0); %but remember to set offset to 0 too! + +%The subsequent method then returns an array (value) of length 20, +%containing data from the 13th until the 32nd element of the waveform. +[value, status] = mocha ('get', pv(3), 'double') + +%END (4) Waveforms and Arrays +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%(5) Handling Enumerated Data Types +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'); +disp('Section (5) Handling Enumerated Data Types'); +disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'); +%Consider pv(4) which is an mbbo record with enumerated value/names +%0/off 1/on 2/{transient state} +%with current value 1, i.e., 'on' + +%Default behaviour is to present the value as a string: +[value, status] = mocha ('get', pv(4)); +%Hence above method will return a value of 'on' +X=[pv(4), 'has value', value]; +disp(X); +%Any MATLAB numberic data type, such as 'int8', 'single' could also be specified +[value, status] = mocha ('get', pv(4), 'uint8'); +%Hence above method would return a value of 1 +X=[pv(4), 'has value', num2str(value)]; +disp(X); + +%For set, the input value can be any valid numeric or string; +%It will be internally converted to an unsigned short before being sent to the IOC. +[status] = mocha ('set', pv(4), 0); % will send the value 0, i.e. 'off' +[status] = mocha ('set', pv(4), 'off'); % will send the value 0, being the value euivalent of the enumerated name +[status] = mocha ('set', pv(4), '0'); %will send an unsigned short value of 0 +[status] = mocha ('set', pv(4), 'anything'); %will complain that this is not a valid enumerated name +[status] = mocha ('set', pv(4), '0anything'); %will convert this to an unsigned short value of 0 + +%END (5) Handling Enumerated Data Types +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%(6) Multiple Scalar Operations, i.e., operations on several PVs with scalar values +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'); +disp('Section (6) Multiple Scalar Operations, i.e., operations on several PVs with scalar values'); +disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'); +%GET: +%Messages are collected and transmitted with one single method invocation +%If Handle/PV points to a WF, only the 1st element of the WF is returned. +%If a data type for the retrieved data is not specified, then the native type +%of the first handle/pv is selected, here (pv(1)) + + +pvInput=[pv(1:3),pv(6)]; +[val, isAllOK, s] = mocha ('getScalarArray', pvInput, 'double'); +% Alternatively +% [val, isAllOK, s] = mocha ('get', pvInput, 'double'); +% may be called; +% mocha('getScalarArray') will then be called internally +[val, isAllOK, s] = mocha ('get', pvInput, 'double') +if isAllOK ~= 1 + for n=1:length(s) + if s(n) ~= 1 + [codes,ctext]=mocha('getStatus', pvInput(n)); + X=['GET: Error in Elem:', num2str(n), pvInput(n), ':']; + Y=[num2str(codes), ctext(1)]; + disp(X); disp(Y); + end + end +end + + +%SET: +val(1)=val(1)+0.001; +[isAllOK, s] = mocha ('setScalarArray', pvInput, val); +% Alternatively +% [isAllOK, s] = mocha ('set', pvInput, val); +% may be called; +% mocha('setScalarArray') will then be called internally + + +[isAllOK, s] = mocha ('set', pvInput, val); + +if isAllOK ~= 1 + for n=1:length(s) + if s(n) ~= 1 + [codes,ctext]=mocha('getStatus', pvInput(n)); + X=['SET: Error in Elem.:', num2str(n), pvInput(n), ':']; + Y=[num2str(codes), ctext(1)]; + disp(X); disp(Y); + end + end +end + +%END (6) Multiple Scalar Operations, i.e., operations on several PVs with scalar values +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%(7) Multiple cell array ('compound') operations, i.e., on several PVS with scalar/vector values +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'); +disp('Section (7) Multiple cell array ("compound") operations, i.e., on several PVS with scalar/vector values'); +disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'); + +%GET +%Note the use of the handles; one could equally use the PV array, pv +[val, isAllOK, s] = mocha ('getCellArray', hpv); +%returns a cell array, wherein the elements are of native data type and can be of any size + +%SET +val{1}=1.111; +val{2}=2.222; +val{3}=(1:256); %wf +val{4}='on'; %mbbo +[isAllOK, s] = mocha ('set', hpv, val{:}); + +%Here, the data type of all returned values is defined to be a string +[val, isAllOK, s] = mocha ('getCellArray', hpv, 'string') + +%END (7) Multiple Scalar Operations, i.e., operations on several PVs with scalar values +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%(8) Multiple Struct operations on several PVS returning PVData Objects plus Multiple Sets for Scalars/Vectors +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'); +disp('Section (8) Multiple Struct operations on several PVS returning PVData Objects plus Multiple Sets for Scalars/Vectors'); +disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'); +%GET +%returns a sequence of pvData structs +%% + +[pvData, isAllOK] = mocha ('getPVArray', pv) +disp('Display all pvData.val values and statuses:'); +%pvData(i) corresponds to the data returned by pv(i) +{pvData.val} +[pvData.status] +%pvData(1:6).ts %timestamps +%[pvData(1:6).alarmStatus] +%[pvData.alarmSeverity] + +%Note: the following method is equivelent to the above +%as it will call getPVArray internally +[pvData, isAllOK] = mocha ('getPV', pv); + + +%returns a sequence of extended (x) pvData structs +%%[pvStruct, isAllOK] = mocha ('getStructArray', pv) +%pvStruct(i) corresponds to the data returned by pv(i) +%%disp('Display all pvStruct as arrays:'); +%%[pvStruct.handle] +%%{pvStruct.pv} +%%{pvStruct.val} +%%[pvStruct.status] +%%{pvStruct.status_str} +%%[pvStruct.alarmStatus] +%%{pvStruct.alarmStatus_str} +%%[pvStruct.alarmSeverity] +%%{pvStruct.alarmSeverity_str} +%%pvStruct.ts +%%pvStruct.epicsTS +%%[pvStruct.alarmSeverity] +%%{pvStruct.alarmSeverity_str} +%pvStruct(1:6).ts %timestamps +%[pvStruct(1:6).alarmStatus] + +%% %%%% +%Note: the following method is equivelent to the above +%as it will call getStructArray internally +[pvStruct, isAllOK] = mocha ('getStruct', pv); +%%%%%%%% + +disp('Alternatively part data (values, statuses only) could also be retrieved with getCellArray:'); +%% %%%% +[val, isAllOK, s] = mocha ('getCellArray', hpv) +%%%%%%%%%%%%%% + + + +%SET -overwrite pvData +pvData(1).val =0.2345; +pvData(2).val =2.6789; +pvData(3).val =(256:512); +pvData(4).val = 'off'; + +%%%%%% +[isAllOK, s] = mocha ('set', hpv, pvData(1:6).val); +%%%%%%%%%%%%%%%%%%% + +%Check values were set +[val, isAllOK, s] = mocha ('getCellArray', hpv) +%%%%%%%%% + +disp('Recall we had previously set an offset for wf of value:'); +offset=mocha('getOffset',hpv(3)) +disp('Setting new offset/nelem for wf has value:'); +offset=mocha('setOffset',hpv(3),0) +%nelem =mocha('setNelem',hpv(3), mocha('getnelemnative',hpv(3)) ) +nelem =mocha('setNelem',hpv(3),10); +disp('Note that setNelem and setOffset are for readback of waveform only'); +%SET +%Another way to set +dd{1} = 3.33; +dd{2} = uint8(4); +dd{3} = [1,2,3,4,5,6,7,8,9,10,11,12,2.6,2.7,2.8,2.9,3.0,3.1,3.2,3.3]; %(2:257); % +dd{4} = 'off'; +dd{5} = 'Enable or Dis-enable BPM'; +dd{6} = 0; +[isAllOK,s] = mocha ('setMany', pv(1:5), dd{1:5}); +%or this will call setMany +dd{4} = 'on'; +[isAllOK,s] = mocha ('set', pv(1:5), dd{1:5}); +%Check values were set +[pvData, isAllOK] = mocha ('getPVArray', hpv(1:5)); +{pvData.val} +pvData(3).val +%END (8) Multiple Struct operations on several PVS returning PVData Objects plus Multiple Sets for Scalars/Vectors +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%(9) Asynchronous interactions and retrieving data from Cache +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'); +disp('Section(9) Asynchronous interactions and retrieving data from Cache'); +disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'); +%GET +%Messages are aggregated until the user decides when to send the messages +%Note that there is no variable for the return data! This will be retrieved +%later through the getCache method + [s] = mocha ('getAsyn', pv(1)); +[isAllOK,s] = mocha ('getAsyn', pv(2:5)); +%Now send the messages +mocha('sendNow'); %optional; otherwise 'getCache' will do the send +%or mocha('caFlush'); + +%getCache methods are used to retrieve the data; +%methods will wait until any outstanding callback is complete or a timeout is reached +[val, s] = mocha('getCache', pv(1), 'double'); + pvData = mocha('getCache', pv(2)); +%get several pvs in one call +[val, isAllOK, s] = mocha('getScalarArrayCache', pv, 'string'); +%or getCache will call getScalarArrayCache +[val, isAllOK, s] = mocha('getCache', pv, 'string') +[val, isAllOK, s] = mocha('getCellArrayCache', pv) +[pvData, isAllOK] = mocha('getPVArrayCache', pv) +%return extended pvStruct +[pvStruct, isAllOK] = mocha('getStructArrayCache', pv) +%SET +%Set messages are by default asynchronous and non-blocking. +%The user may configure any given handle such that the messages are blocking, +%meaning a subsequent set method will wait until the server has reported back to the client: +%BLOCKING: +mocha('setPutWait', pv); %policy changed to blocking for all handles pv(1:6) +status = mocha ('set', pv(1), 0.1); %blocks, status may return a timeout error +%NON_BLOCKING - this is the default +mocha('setPutNoWait', pv); %policy changed to non-blocking for all handles pv(1:6) +status = mocha ('set', pv(1), 0.2); %blocks, status will never return a timeout error +%Want to be sure the value got written? +disp('Executing setAndGet; Return val should equal input value, i.e., 0.3'); +[val, status]= mocha('setAndGet', pv(1), 0.3) %val will be 0.3 on success. +%The above method initiates a set followed immediately by a get. +%The user should be aware that in the event of other applications writing +%to the same epics channel, the possibility exists that this external write +%may occur between the set and subsequent get in the above method. +%The data type of the returned value matches that of the input value. + +%AGGREGATING ASYNCHRONOUS SET OPERATIONS - Can be ignored as user case is expected to be uncommon +%If required set methods can also be aggregated before being sent asynchronously over the network +dd{1} = double(3.3); +dd{2} = uint8(4); +dd{3} = [11,12,13,14,15,6,7,8,9,10,11,12,2.6,2.7,2.8,2.9,3.0,3.1,3.2,3.3]; %(2:257); % +dd{4} = 'off'; +dd{5} = 'Enable or Dis-enable BPM'; +dd{6} = 0; + +mocha('setPutPrepare', pv(1:6)); +s = mocha ('set', pv(1), dd{1}); +s = mocha ('set', pv(2), dd{2}); +s = mocha ('set', pv(3), dd{3}); +s = mocha ('set', pv(4:5), dd{4:5}); +s = mocha ('set', pv(6), dd{6}); +mocha('sendNow'); + +%Note that a subsequent set on the same given channel +%will trigger a 'send' to IOC transaction on the pending set +mocha('setPutPrepare', pv(1:6)); +s = mocha ('set', pv(1), dd{1}); +s = mocha ('set', pv(1), 0.2); %will first trigger a send of the previous 'set' +[val,s]=mocha('get', pv(1)) %a get method will also initiate a send of all previous messages + +%Reset Policy - Remember to reset the policy, e.g., to asynchronous, blocking +mocha('setPutWait', pv); +%or +%Reset Policy - Remember to reset the (default) policy, e.g., to asynchronous, non-blocking, non-aggregating +mocha('setPutNoWait', pv); + +%END (9) Asynchronous interactions and retrieving data from Cache +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%(10) Synchronous Group Operations +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'); +disp('Section(10) Synchronous Group Operations'); +disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'); +% +%Uses the ca_sg functionality which guarantees a set of ca requests have completed, or a timeout is reached +%First define a group; here a simple group of two BPMs +s = mocha('defineGroup', 'gBPM', pv(1:2)); +%First define a group; here a collection of non-related pvs +s = mocha('defineGroup', 'gSnapshot', pv(1:5)); +%Open a group; optional, otherwise first get/set method will establish the connections +gHandle1 = mocha('openGroup', 'gBPM'); +gHandle2 = mocha('openGroup', 'gSnapshot'); + +%A synchronous group can be regarded as a logical software unity; +%*** A pv within a group will have its own, separate handle *** +%as revealed from within the following command +mocha('printHandles'); +%or +[hArray, pvArray]=mocha('getHandles'); +%For example, three ca virual circuits have thus been created for pv(1) +%as this pv exists in its own right, within group 'gBPM' and within group 'gSnapshot' +%Likewise two ca virtual circuits have been created for the waveform in pv(3) +%The various handles for the given pv may be configured independently +%e.g. In the following we will set the nelem for pv(3) (hpv(3)) to 6 +% and the the nelem for pv(3) within the group 'gSnapshot' to 12 +newNelem=mocha('setNelem', pv(3), 6); %corresponds to handle for pv(3) +%set nelements for handle withing group for pv(3) to 12 +handlesWithinGroup=mocha('getHandlesWithinGroup', gHandle2); +newNelem=mocha('setNelem', handlesWithinGroup(3), 12); %handlesWithinGroup(3) corresponds to pv(3) in group 'gSnapshot' +disp('pv(3) should have been read with 6 elements:') +[val,s]=mocha('get', pv(3)); +val +disp('pv(3) should have been read with 12 elements:') +[val,s]=mocha('get', handlesWithinGroup(3)); +val + + +[pvData1, isAllOK] = mocha('getPVGroup', 'gBPM'); %2nd argument could equally have been the group handle, i.e., gHandle1 +[pvData2, isAllOK] = mocha('getPVGroup', gHandle2); %2nd argument could equally have been the group name, i.e., 'gSnapshot' + +%To retrieve extended PVData; +[pvStruct, isAllOK] = mocha('getStructGroup', 'gBPM'); + +%pvData is an array of returned s +pvData2.val +pvData2.status; % int32 +pvData2.alarmStatus; %int16 +pvData2.alarmSeverity; %int16 +pvData2.ts; %[year, month, day, hour, min, sec, nsec] + + +mocha('get',handlesWithinGroup(3)) + +pvData2(3).val=(1:256); +[isAllOK,s]=mocha('setGroup', gHandle2, pvData2.val); +%reset to 256 +mocha('setNelem', handlesWithinGroup(3), 256) +mocha('get',handlesWithinGroup(3)) + + +%Configuring groups through XML - See documentation/talk for XML format +%Here the test.xml contains a group consistimng of 2 BPMs +mocha('loadXMLGroups', 'test.xml'); + +%List Groups and group Members +disp('listGroups:'); +[groups] = mocha('listGroups') +disp('Show members of group gSnapshot:'); +[members]= mocha('listGroupMembers', 'gSnapshot') +disp('Show members of group gTest (as loaded from test.xml):'); +[members]= mocha('listGroupMembers', 'gTest') +%This will only CLOSE and remove groups that have already been OPENED! +%%for i =1:length(groups) +%%mocha('closeGroup', groups{i}) +%%end + +%END (10) Synchronous Group Operations +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%(11) Monitors, either with or without user supplied callbacks (in essence, matlab scripts) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'); +disp('Section(11) Monitors, either with or without user supplied callbacks (in essence, matlab scripts'); +disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'); +%Simple Monitors +monitorID = mocha ('monitor', pv(1)); +[monitorIDArray, isAllOK, statusArray] = mocha ('monitor', pv(1:6)); %start monitors for several pvs/handles +%Once the monitor is started, data may be retrieved via one of the cache methods + +pause(0.1) + +[val,s] = mocha('getCache', pv(1)); %Scalar or vector returned in native data type +[val,s] = mocha('getCache', pv(1), 'double'); %Scalar or vector returned as a MATLAB double +[val,s] = mocha('getCache', pv(1), 'uint8'); %Scalar or vector returned as a MATLAB uint8 + + +[pvData] = mocha('getPVCache', pv(1)) %PVData Object returned with pvData.val in native data type +[pvData] = mocha('getPVCache', pv(1), 'single'); %PVData Object returned with pvData.val as a MATLAB float +[pvData] = mocha('getPVCache', pv(1), 'int32'); %PVData Object returned as a MATLAB int32 + +[pvStruct] = mocha('getStructCache', pv(1)) %Extended (x) mocha closepvData + +s = mocha('monitorStop', pv(1), monitorID); %Stop monitor for pv/handle with given monitorID +s = mocha('monitorStop', pv(1)); %Stop all monitors for this pv/handle +s = mocha('monitorStop', pv(1:6)); %Stop all monitors for these pvs/handles +s = mocha('monitorStop'); %Stop all monitors for all pvs/handles + + +%Monitors with Actions, i,e, callback of MATLAB script + +%Need to give the numeric value of the handle as input argument to monitorAction +monAction=['monitorAction(', num2str(hpv(1)), ')'] ; +%The above reads monAction = 'monitorAction(1)' +%Here monitorAction(1) refers to a Matlab Script monitorAction.m +%that takes a single input argument, which is the handle of the monitored channel + +monitorID= mocha('monitor',hpv(1),monAction); + +%Mulitple monitors with actions: +%monAction2=['monitorAction(', num2str(hpv(2)), ')'] ; +%[monitorID] = mocha('monitor', hpv(1:2), monAction, monAction2); + +%The monitorAction.m script will typically retrieve data from Cache as follows: +%[val,status]=mocha ('getCache', varargin{1}); + +mocha('monitorFlushEvent', pv(1)); %will execute the MATLAB script monitorAction.m if new data has arrived +mocha('monitorFlushEvent'); %will execute all 'actions' for all 'handles' that have received new data + +%The above command is used in conjunction with MATLAB timer (as for MCA's mcamontimer.m) +obj.t = timer('TimerFcn', 'mocha(''monitorFlushEvent'')', 'Period', 2.0, 'ExecutionMode', 'fixedSpacing'); +%Else if double quotes cannot be used in the above; here's a way around the problem: +%obj.t = timer('TimerFcn', 'mocha(402)', 'Period', 2.0, 'ExecutionMode', 'fixedSpacing'); +start(obj.t); +disp ('Callback for monitors for 5 seconds') +for n=1:5 + mocha('set', pv(1), n); %See the script be executed + pause(0.5); +end +stop(obj.t); + +%END Monitors, either with or without user supplied callbacks (in essence, matlab scripts) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% (12) Control system parameters, i.e. operating limits, engineerimg units +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'); +disp('Section(12) Control system parameters, i.e. operating limits, engineerimg units'); +disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'); +[ctrlData] = mocha('getCtrl', hpv(1)); +%Usually it is sufficient to use the getCtrlCache method +[ctrlData] = mocha('getCtrlCache', hpv(1)); +ctrlData +% This is what an output may look like for an ao/ai record +%{ + handle: 1 + pv: 'ARIDI-BPM-01LE:X-AVG' + val: 3.2000 + status: 1 + alarmStatus: 0 + alarmSeverity: 0 + precision: 6 + units: 'mm' + noEnumStrings: 0 + enumStrings: {1�0 cell} + upperDisplayLimit: 2 + lowerDisplayLimit: -2 + upperAlarmLimit: NaN + lowerAlarmLimit: NaN + upperWarningLimit: NaN + lowerWarningLimit: NaN + upperControlLimit: 2 + lowerControlLimit: -2 +%} +[ctrlData] = mocha('getCtrlCache', hpv(4)); +ctrlData +% This is what an output may look like for an mbbo/i record +%{ + handle: 2 + pv: 'ARIDI-BPM-01LE:SET-ENABLE' + val: 'off' + status: 1 + alarmStatus: 0 + alarmSeverity: 0 + precision: 0 + units: '' + noEnumStrings: 3 + enumStrings: {'off' 'on' 'monitor'} + upperDisplayLimit: 0 + lowerDisplayLimit: 0 + upperAlarmLimit: 0 + lowerAlarmLimit: 0 + upperWarningLimit: 0 + lowerWarningLimit: 0 + upperControlLimit: 0 + lowerControlLimit: 0 +%} + +% +%END (12) Control system parameters, i.e. operating limits, engineerimg units +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% (13) Retrieve channel medadata, e.g., data type, native no. elements, connection state, read/write access, etc. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'); +disp('Section(13) Retrieve channel medadata, e.g., data type, native no. elements, connection state, read/write access, etc. '); +disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'); + +iStruct=mocha('getInfo', pv(1)); +iStruct +% This is what an output may look like: +% The members connectFlag, accessRead, and accessWrite are all of MATLAB data type, logical +%{ + handle: 1 + pv: 'ARIDI-BPM-01LE:X-AVG' + channelID: '0x7f46fc879ae0' + connectFlag: 1 + hostName: 'psi-softioc-2.psi.ch:45408' + dataType: 'DBR_DOUBLE' + className: 'ai' + accessRead: 1 + accessWrite: 1 + nelem: 1 + connectionState: 'CA_OP_CONN_UP' +%} + +% +%END (13) Retrieve channel medadata, e.g., data type, native no. elements, connection state, read/write access, etc. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% (14) Setting timeouts for set/get operations +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'); +disp('Section(14) Setting timeouts for set/get operations'); +disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'); +%Timeouts in CAFE are self-regulating and are regulated by +%the following parameters in defines.h in the CAFE livrary +%const bool DEFAULT_SELF_GOVERNING_TIMEOUT = true; +%const unsigned short DEFAULT_PEND_IO_NO_TRIES = 2; +%const double DEFAULT_PEND_IO_INCREMENT_TIME = 2.0; + +%Self governing timeouts may be turned off/on for all handles, +%or on a per handle basis + +%Make true (default) for handle hpv(1) +mocha('setselfgoverningtimeout', pv(1), true); + +%Make true for all handles +mocha('setselfgoverningtimeout', true); + + +%Timeouts can be set separately for blocking SET/GET operations +%either globally or on a per handle basis +[t] = mocha('getTimeout', pv(1)); +%t(1) is timeout for a blocking put operation +%t(2) is timeout for a blocking get operation + +%the minimum timeout is returned from among all handles +[t] = mocha('getTimeout'); +%t(1) is minimum put timeout from among all handles +%t(2) is minimum get timeout from among all handles + +%Timeouts can be set in a number of ways, for all handles +%or on a per handle basis + +%set both put and get timeouts for handle hpv(1) to 10.0 seconds +status=mocha('setTimeout', pv(1), 10.0); + +%set both put and get timeouts for all handles to 10.0 seconds +status=mocha('setTimeout', 10.0); + +%set put timeout for handle hpv(1) to 5.0 seconds +status=mocha('setTimeoutPut', pv(1), 5.0); + +%set put timeouts for all handles to 5.0 seconds +status=mocha('setTimeoutPut', 5.0); + +%set get timeout for handle hpv(1) to 10.0 seconds +status=mocha('setTimeoutGet', pv(1), 10.0); + +%set put timeouts for all handles to 10.0 seconds +status=mocha('setTimeoutGet', 10.0); + +% +%END (14) Setting timeouts for set/get operations +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% (15) Setting synchronous group timeouts for set/get operations +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'); +disp('Section(15) Setting synchronous group timeouts for set/get operations'); +disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'); + +%Self governing timeouts may be turned off/on for all group handles, +%or on a per group handle basis + +%Make true (default) for handle hpv(1) +mocha('setSGselfgoverningtimeout', gHandle1, true); + +%Make true for all handles +mocha('setSGselfgoverningtimeout', true); + + +%Timeouts can be set separately for blocking SET/GET operations +%either globally or on a per grop handle basis +[t] = mocha('getSGTimeout',gHandle1); +%t(1) is timeout for a group put operation +%t(2) is timeout for a grop get operation + +%the minimum timeout is returned from among all handles +[t] = mocha('getSGTimeout'); +%t(1) is minimum put timeout from among all group handles +%t(2) is minimum get timeout from among all group handles + +%Timeouts can be set in a number of ways, for all gourp handles +%or on a per grop handle basis + +%set both put and get timeouts for group handle, gHandle1, to 10.0 seconds +status=mocha('setSGTimeout', gHandle1, 10.0); + +%set both put and get timeouts for all group handles to 10.0 seconds +status=mocha('setSGTimeout', 10.0); + +%set put timeout for group handle, gHandle1, to 5.0 seconds +status=mocha('setSGTimeoutPut', gHandle1, 5.0); + +%set put timeouts for all group handles to 5.0 seconds +status=mocha('setSGTimeoutPut', 5.0); + +%set get timeout for group handle, gHandle1, to 10.0 seconds +status=mocha('setTimeoutGet', gHandle1, 10.0); + +%set put timeouts for all group handles to 10.0 seconds +status=mocha('setSGTimeoutGet', 10.0); + +% +%END (15) Setting synchronous group timeouts for set/get operations +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% (16) Special Methods, e.g., setAndGet +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'); +disp('Section(16) Special Methods, e.g., setAndGet, setAndMatch '); +disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'); + + +%%Several specialized methods exist within the CAFE library, +%%such as setAndMatch which can set a number of PVs to a given value +%%and then examines a given collection of readback PVS. +%%Method verifies whether or not the set/readback values agree within +%%the given tolerance and timeout. Useful for, e.g., ID Gap Scans, +%%Other specialized methods can be exposed to mocha on request + +% \brief Set Channels followed by a corresponding readback of Channels +% Method verifies whether or not the set/readback values agree within +% the given tolerance and timeout. ICAFE_NORMAL is returned as soon as +% a match is reached else ECAFE_TIMEOUT_SET_AND_MATCH if timeout. +% \param 1 input: 'setAndMatch' +% \param 2 input: array of handles/pvs to set +% \param 3 input: array of values to set +% \param 4 input: array of handles/ov of readback channel +% \param 5 input: tolerance (+-) margin +% \param 6 input: timeout value; maximum time allowed for agreement to occur +% \param 7 input: printFlag bool, set to true for diagnostics +% \return ECA_NORMAL if all OK else first ECAFE error encountered, else +% ECAFE_TIMEOUT_SET_AND_MATCH if timeout + +% For the purpose of this example, the readbnack channels are the same as +% the input channels thus ensuring that a match is found +status=mocha ('setAndMatch', pv(1:2), [1.1,2.2], pv(1:2), 0.01, 5.0, true); + +%%Another simple method is the setAndGet Method +%%Set a PV and immediately retrieve its value + +%The method (previously presente in (9) above, initiates a set and is +%followed immediately by a get. +%The user should be aware that in the event of other applications writing +%to the same epics channel, the possibility exists that this external write +%may occur between the set and subsequent get within the 'setAndGet'. + +setValue=0.4; +[getValue, status] = mocha ('setAndGet', pv(1), setValue) +%The data type of the returned value matches that of the input value. + +% +%END (16) Special Methods, e.g., setAndGet +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% (17) Gracefully terminate CAFE +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'); +disp('Section(17) Gracefully terminate CAFE '); +disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'); + + +%Stops all monitors (if any) +%Closes all channels +%Releases all CA resources +mocha ('close') +% +%END (17) Gracefully terminate CAFE +%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + + diff --git a/scripts/mcaunlock.m b/scripts/mcaunlock.m index 1d97e26..3bcdeeb 100644 --- a/scripts/mcaunlock.m +++ b/scripts/mcaunlock.m @@ -8,4 +8,4 @@ function mcaunlock; % loosing channel access connections. %mca(0); mocha('mexUnlock'); -disp('mca mex-file is now UNLOCKED'); +%disp('mca mex-file is now UNLOCKED');