diff --git a/linux-x86_64/2024b/cadelmon.m b/linux-x86_64/2024b/cadelmon.m new file mode 100755 index 0000000..9021cfe --- /dev/null +++ b/linux-x86_64/2024b/cadelmon.m @@ -0,0 +1,23 @@ +function cadelmon(channel) +% cadelmon('channel') +% Deletes monitor callback on EPICS channel + +% translate pv name to handle +if ischar(channel) + pv = mcaisopen(channel); + if pv == 0 + return; + end +elseif isnumeric(channel) + pv = channel; +else + error ('first argument must be channel name or handle'); +end + +% delete monitor +mcaclearmon(pv); + +% if no monitor left then stop monitoring +if isempty(mcamon) && mcamontimer + mcamontimer('stop') +end diff --git a/linux-x86_64/2024b/caget.m b/linux-x86_64/2024b/caget.m new file mode 100755 index 0000000..733af0a --- /dev/null +++ b/linux-x86_64/2024b/caget.m @@ -0,0 +1,108 @@ +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', 1.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); + +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; + + +if (pvCtrl.noEnumStrings>0) + value.val_str = value.val; + value.val = mocha('getCache',pv,'int8'); +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/linux-x86_64/2024b/cainfo.m b/linux-x86_64/2024b/cainfo.m new file mode 100755 index 0000000..da2bb20 --- /dev/null +++ b/linux-x86_64/2024b/cainfo.m @@ -0,0 +1,34 @@ +function value = cainfo(pvname) +% cainfo('pvname') returns handle,element count, native type, state, ... +% + + +mcaNoConnection ={'unknown', 'disconnected','Disconnected due to server or network problem'}; +mcaConnection ={'known', 'connected','Normal connection'}; +mcaClosedConnection={'unknown', 'disconnected','Permanently disconnected (cleared)'}; + + +value=struct('Handle',{}, 'PVName',{}, 'ElementCount',{},'NativeType',{},'State',{},'MCAMessage',{},'Host',{},'Units',{}); +chInfo=mocha ('getChannelInfo', pvname); +pvCtrl=mocha ('getCtrlCache', pvname); +value(1).Handle= mocha('getHandleFromPV', pvname); +value(1).PVName= mocha('getPVFromHandle', value(1).Handle); +value(1).ElementCount=chInfo.nelem; +nativeType=strsplit(chInfo.dataType,'_'); +value(1).NativeType=nativeType{2}; + +if (chInfo.connectFlag==1) + value(1).State=mcaConnection{2}; + value(1).MCAMessage=mcaConnection{3}; +else + value(1).State=mcaNoConnection{2}; + value(1).MCAMessage=mcaNoConnection{3}; +end + + +%value(1).MCAMessage=mocha('statusInfo', mocha('getStatus', pvname)); +value(1).Host =chInfo.hostName; +value(1).Units=pvCtrl.units; + +%value(1)=setfield(value(1),'Units',pvCtrl.units) + diff --git a/linux-x86_64/2024b/camon.m b/linux-x86_64/2024b/camon.m new file mode 100755 index 0000000..176c98f --- /dev/null +++ b/linux-x86_64/2024b/camon.m @@ -0,0 +1,62 @@ +function camon(channel,callback,userarg) +% camon('channel', 'callback') +% camon('channel', 'callback', userarg) +% camon('channel', @callback) +% camon('channel', @callback, userarg) +% +% Installs a callback function (given as string or handle) +% on an EPICS channel. +% Whenever the channel updates, the callback is called +% with a structure as defined below and an optional +% numeric, string, or matrix user argument +% +% callback argument structure 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 +% +% A monitor can be deleted with +% cadelmon ('channel') + + +% initialize monitoring the first time +if ~mcamontimer + mcamontimer('start'); +end + +% translate channel name to handle +if ischar(channel) + pv = mcacheckopen(channel); + if pv == 0 + error('EPICS channel %s not found', channel); + end +elseif isnumeric(channel) + pv = channel; +else + error ('usage: camon(''channel'',@callback,userarg)'); +end + +% callback can be string or function handle -- we need string +if nargin>1 + if isa(callback,'function_handle') + callback = func2str(callback); + elseif ~ischar(callback) + error ('usage: camon(''channel'',@callback,userarg)'); + end +end + +% install monitor +if nargin==1 + mcamon(pv); + return +elseif nargin==2 + cb=sprintf('%s(caget(%d,1))',callback,pv); +else + cb=sprintf('%s(caget(%d,1),''%s'')',callback,pv,mat2str(userarg)); +end +disp(pv) +disp(cb) +mcamon(pv, cb); diff --git a/linux-x86_64/2024b/caput.m b/linux-x86_64/2024b/caput.m new file mode 100755 index 0000000..748202e --- /dev/null +++ b/linux-x86_64/2024b/caput.m @@ -0,0 +1,30 @@ +function sts = caput(pvname, value) +% sts=caput('pvname',value) sets the value of EPICS PV 'pvname'. + +% +channel=pvname; + +if ischar(channel) + pv = mocha('open',channel); + + if mocha('isConnected', channel) == false + mocha('openNowAndWait', 1.5) + end + + if mocha('isConnected', channel) == false + error('EPICS channel %s not found', channel); + end +elseif isnumeric(channel) + + if mocha('isConnected', channel) == false + error('EPICS channel with handle %d not connected', channel); + end + pv = channel; + +else + error ('First argument must be channel name or handle'); +end + + +sts= mocha('set', pv, value); + diff --git a/linux-x86_64/2024b/example.m b/linux-x86_64/2024b/example.m new file mode 100644 index 0000000..7cece65 --- /dev/null +++ b/linux-x86_64/2024b/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/linux-x86_64/2024b/macchinettaSwitch.o b/linux-x86_64/2024b/macchinettaSwitch.o new file mode 100644 index 0000000..1a7b7d3 Binary files /dev/null and b/linux-x86_64/2024b/macchinettaSwitch.o differ diff --git a/linux-x86_64/2024b/mcaalarm.m b/linux-x86_64/2024b/mcaalarm.m new file mode 100644 index 0000000..c4593e1 --- /dev/null +++ b/linux-x86_64/2024b/mcaalarm.m @@ -0,0 +1,36 @@ +function varargout = mcaalarm(varargin) +%MCAALARM - read alarm status and severity for PVs previously read with MCAGET or MCAMON +% +% VALUE = MCAALARM(HANDLE) +% returns the status and severity of a PV specified by integer HANDLE: +% +% VALUE is a structure: +% 'status' : Status code +% 'severity': Severity code +% +% Refer to the EPICS header file "alarmString.h" for the code definitions. +% +% [VALUE1, ... VALUEN] = MCAALARM(HANDLE1, ... , HANDLEN) +% returns status and severity of multiple PVs of any type and length +% Number of outputs must match the number of inputs +% +% See also MCAGET, MCAMON. +% +if nargin<1 + error('No arguments were specified in mcaalarm') +elseif nargin==1 + result{1} = mocha('getAlarm',varargin{1}); %mca(61,varargin{1}); + varargout{1}.status = result{1}(1,1); + varargout{1}.severity = result{1}(1,2); +elseif nargin>1 + if nargin ~= nargout + error('Number of outputs must match the number of inputs') + end + %[result{1:nargin}] = mca(61,varargin{:}); + for k = 1:nargin + [result{k}] = mocha('getAlarm',varargin{k}); + varargout{k}.status=result{k}(1,1); + varargout{k}.severity=result{k}(1,2); + end +end + diff --git a/linux-x86_64/2024b/mcacache.m b/linux-x86_64/2024b/mcacache.m new file mode 100644 index 0000000..cd1f038 --- /dev/null +++ b/linux-x86_64/2024b/mcacache.m @@ -0,0 +1,40 @@ +function varargout = mcacache(varargin) +%MCACACHE - reads locally cached value of a PV. +% MCACACHE does NOT communicate with the server or use resources of CA library +% +% VALUE = MCACACHE(HANDLE) returns a value of a PV by integer HANDLE +% The type (EPICS strings are returned as MATLAB strings) +% All numeric EPICS types returned are as MATLAB double +% If a PV is is a waveform VALUE is a vector +% +% [ VALUE1 , ... VALUEN ] = MCACACHE(HANDLE1, ... , HANDLEN) +% returns values of multiple PV's. +% Number of outputs must match the number of inputs +% +% Notes: The cache value for a PV does not exist until the first use of a +% monitor on that PV +% See also: MCAMON + +if nargin>1 && nargin~=nargout + error('Number of outputs must match the number of inputs') +end + + +for k = 1:nargin + [varargout{k}] = mocha('getCache',varargin{k}); + +end + +%for k = 1:nargin +% scalarValues(k) = varargin{k}; +%end + +%[a,isAllOk,s]=mocha('getScalarArrayCache',scalarValues); + +%for k = 1:nargin +% [varargout{k}]= a(k); +%end +% + +%[varargout{1:nargin}] = mca(300,varargin{:}); + diff --git a/linux-x86_64/2024b/mcacheck.m b/linux-x86_64/2024b/mcacheck.m new file mode 100644 index 0000000..6c48338 --- /dev/null +++ b/linux-x86_64/2024b/mcacheck.m @@ -0,0 +1,20 @@ +function varargout = mcacheck(varargin) +%MCACHECK - Same as MCASTATE +% See also MCAOPEN + +if nargin > 0 + %varargout{1} = mca(13,varargin{:}); + for k = 1:nargin + if mocha('isConnected', varargin{k}) == true + isConnected(k) = uint16(1); + else + isConnected(k) = uint16(0); + end + end + varargout{1} = isConnected; +else + [h,pv,state] = mocha('getHandleStates'); + %[varargout{1}, varargout{2}] = mca(12); + varargout{1} = h; + varargout{2} = state; +end diff --git a/linux-x86_64/2024b/mcacheckopen.m b/linux-x86_64/2024b/mcacheckopen.m new file mode 100644 index 0000000..c6bde51 --- /dev/null +++ b/linux-x86_64/2024b/mcacheckopen.m @@ -0,0 +1,48 @@ +function varargout = mcacheckopen(varargin) +%MCACHECKOPEN - returns handle(s) to PV(s) +% Returns existing handles for PVs already connected, +% opens new connections otherwise. +% Returns 0 for PVs that failed to connect. +% +% HANDLE = MCACHECKOPEN('NAME') +% +% [HANDLE1, ... , HANDLEN] = MCACHECKOPEN('PVNAME1', ... , 'PVNAMEN') +% +% HANDLES = MCACHECKOPEN(NAMES) +% When NAMES is a cell array of strings, HANDLES is a numeric array of +% handles +% +% Note: +% In principle, one should open, use, close PVs. +% But in some cases the bookkeeping of PV handles might +% be a bit too much for quick script hacks, +% in which case mcacheckopen can help with re-use of +% existing handles for PVs that were opened earlier yet +% their handles are lost. +% +% See also MCAOPEN, MCAISOPEN + +if iscellstr(varargin{1}) + varargout{1} = zeros(size(varargin{1})); + + for i=1:length(varargin{1}) + + varargout{1}(i) = mcaisopen(varargin{1}{i}); + if ~varargout{1}(i) + + varargout{1}(i) = mcaopen(varargin{1}{i}); + end + end +else + + + for i=1:nargin + + varargout{i} = mcaisopen(varargin{i}); + if ~varargout{i} + + varargout{i} = mcaopen(varargin{i}); + end + end +end + diff --git a/linux-x86_64/2024b/mcaclearmon.m b/linux-x86_64/2024b/mcaclearmon.m new file mode 100644 index 0000000..6538893 --- /dev/null +++ b/linux-x86_64/2024b/mcaclearmon.m @@ -0,0 +1,19 @@ +function mcaclearmon(varargin) +%MCACLEARMON - uninstall monitors, previously installed with MCAMON +% +% MCACLEARMON(H1,H2,...,HN) +% H1,H2..,HN - integer channel handles +% +% Note: Monitors can be installed with MCAMON and cleared with +% MCACLEARMON any number of times. +% +% See also MCAMON, MCAMONTIMER, MCACACHE + +if nargin <1 + error('Must specify channel handles to close'); +else + for i=1:nargin + %mca(200,varargin{i}) + mocha('monitorStop',varargin{i}) + end +end diff --git a/linux-x86_64/2024b/mcaclose.m b/linux-x86_64/2024b/mcaclose.m new file mode 100644 index 0000000..776ea40 --- /dev/null +++ b/linux-x86_64/2024b/mcaclose.m @@ -0,0 +1,22 @@ +function mcaclose(varargin) +%MCACLOSE - permanently closes channels +% MCACLOSE(H1,H2,...,HN) closes the channels identified by their +% integer handles, previously opened with MCAOPEN. +% MCACLOSE(H) is the same for the case that H is an array of handles. +% +% Note: Once a channel is closed, it can not be used +% by MCAGET,MCAPUT or MCAMON. It can not be reopened. +% Use MCAOPEN again in order to connect to the same PV. +% +% See also MCAOPEN, MCASTATE, MCAINFO +if nargin <1 + error('Must specify channel handles to close'); +else + for i=1:nargin + pvs = varargin{i}; + for j=1:length(pvs) + %mca(5, pvs(j)) + mocha('close', pvs(j)) + end + end +end diff --git a/linux-x86_64/2024b/mcadebug.m b/linux-x86_64/2024b/mcadebug.m new file mode 100644 index 0000000..6c1cb33 --- /dev/null +++ b/linux-x86_64/2024b/mcadebug.m @@ -0,0 +1,12 @@ +function mcadebug(onoff) +%MCADEBUG - Enable/disable debugging +% +% Used only for development, not user-callable. +if onoff + %mca(9999, 1); + disp('Not relevant to mocha'); +else + %mca(9999); + disp('Not relevant to mocha'); +end + diff --git a/linux-x86_64/2024b/mcaegu.m b/linux-x86_64/2024b/mcaegu.m new file mode 100644 index 0000000..6849338 --- /dev/null +++ b/linux-x86_64/2024b/mcaegu.m @@ -0,0 +1,34 @@ +function varargout = mcaegu(varargin) +%MCAEGU - read engineering units from PV's +% +% VALUES = MCAEGU(HANDLE) returns a string array of enum strings of the +% PV specified by integer HANDLE. +% The function does not handle arrays of PV handles, but only a single PV at at time. +% +% +% Error handling: +% An empty cell string array will be returned if the PV type is not ENUM. +% A matlab exception will be thrown when the PV handle is invalid, +% i.e. not the result of a successful MCAOPEN. +% Furthermore, an error can result from a 'get' timeout, +% configurable via MCATIMEOUT. +% In addition, an error can result from a network disconnect. +% In principle, one can check beforehand via MCASTATE, but since +% a disconnect might happen just between the sucessful MCASTATE call +% and the following MCAGET, the only safe thing might be to surround +% MCAGET calls with TRY....CATCH. +% +% See also TRY, CATCH, MCASTATE, MCATIMEOUT, MCAPUT +if nargin<1 + error('No arguments were specified in mcaget') +elseif nargin==1 + if length(varargin{1})>1 + error('Only single PV can be handled at a time') + else + pvCtrl=mocha('getCtrlCache', varargin{1}); + varargout{1} = {pvCtrl.units}; %mca(41,varargin{1}); + end +elseif nargin>1 + error('Only single PV can be handled at a time') +end + diff --git a/linux-x86_64/2024b/mcaenums.m b/linux-x86_64/2024b/mcaenums.m new file mode 100644 index 0000000..e43afbe --- /dev/null +++ b/linux-x86_64/2024b/mcaenums.m @@ -0,0 +1,39 @@ +function varargout = mcaenums(varargin) +%MCAENUMS - read enum strings from PV's +% +% VALUES = MCAENUMS(HANDLE) returns a string array of enum strings of the +% PV specified by integer HANDLE. +% The function does not handle arrays of PV handles, but only a single PV at at time. +% +% +% Error handling: +% An empty cell string array will be returned if the PV type is not ENUM. +% A matlab exception will be thrown when the PV handle is invalid, +% i.e. not the result of a successful MCAOPEN. +% Furthermore, an error can result from a 'get' timeout, +% configurable via MCATIMEOUT. +% In addition, an error can result from a network disconnect. +% In principle, one can check beforehand via MCASTATE, but since +% a disconnect might happen just between the sucessful MCASTATE call +% and the following MCAGET, the only safe thing might be to surround +% MCAGET calls with TRY....CATCH. +% +% See also TRY, CATCH, MCASTATE, MCATIMEOUT, MCAPUT +if nargin<1 + error('No arguments were specified in mcaget') +elseif nargin==1 + if length(varargin{1})>1 + error('Only single PV can be handled at a time') + else + pvCtrl=mocha('getCtrlCache', varargin{1}); + ens13=pvCtrl.enumStrings; + ens=cell(max(1,pvCtrl.noEnumStrings),1); + for k=1:pvCtrl.noEnumStrings + ens(k)=ens13(k); + end + varargout{1} = ens; %mca(40,varargin{1}); + end +elseif nargin>1 + error('Only single PV can be handled at a time') +end + diff --git a/linux-x86_64/2024b/mcaexit.m b/linux-x86_64/2024b/mcaexit.m new file mode 100644 index 0000000..e93988b --- /dev/null +++ b/linux-x86_64/2024b/mcaexit.m @@ -0,0 +1,5 @@ +function mcaexit() +%MCAEXIT - Shut down channel access... +% +% Disconnects all PVs. +mocha('close') %mca(999) diff --git a/linux-x86_64/2024b/mcaget.m b/linux-x86_64/2024b/mcaget.m new file mode 100644 index 0000000..19f0bea --- /dev/null +++ b/linux-x86_64/2024b/mcaget.m @@ -0,0 +1,71 @@ +function varargout = mcaget(varargin) +%MCAGET - read values from PV's +% +% VALUE = MCAGET(HANDLE) returns a value of a PV specified by integer HANDLE. +% Type of return value depends on the native type and the number of elements +% in the EPICS record: +% +% EPICS strings are returned as MATLAB strings +% EPICS array of strings - MATLAB cell array of strings +% All numeric EPICS types are returned as MATLAB double arrays +% +% VALUES = MCAGET(HANDLES) an easy get for a group of scalar numeric PV's +% HANDLES - array of handles +% VALUES - numeric array of values. +% If any of the PVs is a waveform, +% only the first element is returned +% +% [VALUE1, ... VALUEN] = MCAGET(HANDLE1, ... , HANDLEN) +% returns values of multiple PV's of any type and length +% Number of outputs must match the number of inputs +% +% Error handling: +% A matlab exception will be thrown when any of the PVs are invalid, +% i.e. not the result of a successful MCAOPEN. +% Furthermore, an error can result from a 'get' timeout, +% configurable via MCATIMEOUT. +% In addition, an error can result from a network disconnect. +% In principle, one can check beforehand via MCASTATE, but since +% a disconnect might happen just between the sucessful MCASTATE call +% and the following MCAGET, the only safe thing might be to surround +% MCAGET calls with TRY....CATCH. +% +% See also TRY, CATCH, MCASTATE, MCATIMEOUT, MCAPUT +if nargin<1 + error('No arguments were specified in mcaget') +elseif nargin==1 + if length(varargin{1})>1 + [a, isallOK]=mocha('getScalarArray', varargin{1}, 'double'); + + varargout{1} = [a]; %mocha('getScalarArray', varargin{1}); %mca(51,varargin{1}); + else + chInfo=mocha('getInfo', varargin{1}); + if( strcmp(chInfo.dataType,'DBR_ENUM') ) + varargout{1} = mocha('get', varargin{1},'double'); + else + varargout{1} = mocha('get', varargin{1}); %mca(50,varargin{1}); + end + end +elseif nargin>1 + if nargin ~= nargout + error('Number of outputs must match the number of inputs') + end + [a, isallOK]=mocha('getStructArray', [varargin{:}]); + for k=1:length(a) + chInfo=mocha('getInfo', varargin{k}); + if( length(a(k).val) ==1 && strcmp(chInfo.dataType,'DBR_ENUM') ) + varargout{k}=mocha('getCache', varargin{k}, 'double'); + %if (length(a(k).val)==1 && iscell(a(k).val)) + % varargout{k}=a(k).val{1}; + else + if (length(a(k).val)==1 && iscell(a(k).val)) + varargout{k}=a(k).val{1}; + else + varargout{k}=a(k).val; + end + + end + end + %[varargout{1:nargin}] mca(50,varargin{:}); +end + diff --git a/linux-x86_64/2024b/mcagets.m b/linux-x86_64/2024b/mcagets.m new file mode 100644 index 0000000..c0379a9 --- /dev/null +++ b/linux-x86_64/2024b/mcagets.m @@ -0,0 +1,76 @@ +function varargout = mcagets(varargin) +%MCAGETS - read values from PV's, with string output for ENUMs +% +% VALUE = MCAGETS(HANDLE) returns a value of a PV specified by integer HANDLE. +% Type of return value depends on the native type and the number of elements +% in the EPICS record: +% +% EPICS strings are returned as MATLAB strings +% EPICS array of strings - MATLAB cell array of strings +% All numeric EPICS types are returned as MATLAB double arrays +% This routine returns the string value of ENUM types, when the input +% parameter is a single handle. Otherwise this routine behaves +% identically to MCAGET +% +% VALUES = MCAGETS(HANDLES) an easy get for a group of scalar numeric PV's +% HANDLES - array of handles +% VALUES - numeric array of values. +% If any of the PVs is a waveform, +% only the first element is returned +% +% [VALUE1, ... VALUEN] = MCAGETS(HANDLE1, ... , HANDLEN) +% returns values of multiple PV's of any type and length +% Number of outputs must match the number of inputs +% +% Error handling: +% A matlab exception will be thrown when any of the PVs are invalid, +% i.e. not the result of a successful MCAOPEN. +% Furthermore, an error can result from a 'get' timeout, +% configurable via MCATIMEOUT. +% In addition, an error can result from a network disconnect. +% In principle, one can check beforehand via MCASTATE, but since +% a disconnect might happen just between the sucessful MCASTATE call +% and the following MCAGET, the only safe thing might be to surround +% MCAGET calls with TRY....CATCH. +% +% See also TRY, CATCH, MCASTATE, MCATIMEOUT, MCAPUT +if nargin<1 + error('No arguments were specified in mcaget') +elseif nargin==1 + if length(varargin{1})>1 + [a, isallOK]=mocha('getScalarArray', varargin{1}, 'double'); + varargout{1} = [a]; %mca(51,varargin{1}); + else + + varargout{1} = mocha('get', varargin{1}); + + %if(strcmp(mca(43,varargin{1}),'ENUM')) + % enumvalues=mca(40,varargin{1}); + % varargout{1}= enumvalues{mca(50,varargin{1})+1}; + % else + % varargout{1} =mca(50,varargin{1}); + % end + end +elseif nargin>1 + if nargin ~= nargout + error('Number of outputs must match the number of inputs') + end + [a, isallOK]=mocha('getStructArray', [varargin{:}]); + for k=1:length(a) + chInfo=mocha('getInfo', varargin{k}); + if( length(a(k).val) ==1 && strcmp(chInfo.dataType,'DBR_ENUM') ) + varargout{k}=mocha('getCache', varargin{k}, 'double'); + + else + if (length(a(k).val)==1 && iscell(a(k).val)) + varargout{k}=a(k).val{1}; + else + varargout{k}=a(k).val; + end + end + end + %[varargout{1:nargin}] mca(50,varargin{:}) + +end + + diff --git a/linux-x86_64/2024b/mcainfo.m b/linux-x86_64/2024b/mcainfo.m new file mode 100644 index 0000000..1ad07d7 --- /dev/null +++ b/linux-x86_64/2024b/mcainfo.m @@ -0,0 +1,86 @@ +function varargout = mcainfo(varargin); +%MCAINFO - get connection status and other information about a PV +% INFO = MCAINFO(PV) returns information on a single PV +% PV can be a string PV name or an integer handle +% Returns a 1-by-1 structure with fields: +% +% Handle +% PVName +% ElementCount: +% NativeType { STRING | INT | FLOAT | ENUM | CHAR | DOUBLE } +% State { connected | disconnected } +% MCAMessage +% Host +% +% [HANDLES, INFO] = MCAINFO with no argument returns information on +% all open channels in a structure array. +% HANDLES is a numeric array of handles +% INFO is a structure array of inoformation on the PV in the +% same format as above +% +% Note: A channel may become disconnected +% due to a server or network problem. This will be reflected in +% MCAMessage field. Any attempts to read, write or monitor this channel +% will return an error. CA library will periodically attempt to reestablish +% connection without any action required from the user. +% When the connection is closed by the user with MCACLOSE, +% that PV handle becomes invalid, and attempts to call MCAINFO +% will result in an error. +% +% See also: MCAOPEN MCACLOSE MCASTATE +value=struct('Handle',{}, 'PVName',{}, 'ElementCount',{},'NativeType',{},'State',{},'MCAMessage',{},'Host',{},'Units',{}); + + +mcaNoConnection ={'unknown', 'disconnected','Disconnected due to server or network problem'}; +mcaConnection ={'known', 'connected','Normal connection'}; +mcaClosedConnection={'unknown', 'disconnected','Permanently disconnected (cleared)'}; + +if nargin>0 + if ischar(varargin{1}) + %[handles, names] = mca(3); + %matchfound = find(strcmp(varargin{1},names)); + %if isempty(matchfound) + % error(['No open channels found for a PV: ',varargin{1}]); + %end + + %h = handles(matchfound); + h(1)=mocha('getHandleFromPV',varargin{1}); + if (h(1)==0) + error(['No open channels found for a PV: ',varargin{1}]); + end + elseif isnumeric(varargin{1}) + h(1)=(varargin{1}); + else + error('Argument must be a string PV Name or an integer handle'); + end + %varargout{1} = mca(11,h); +else % Return info on all channels + %[varargout{1} varargout{2}] = mca(10); + [h,pv]=mocha('getHandles'); +end + +for k=1:length(h) + chInfo=mocha ('getChannelInfo', h(k)); + pvCtrl=mocha ('getCtrlCache', h(k)); + value(k).Handle=h(k); + value(k).PVName= mocha('getPVFromHandle', h(k)); + value(k).ElementCount=chInfo.nelem; + nativeType=strsplit(chInfo.dataType,'_'); + value(k).NativeType=nativeType{2}; + if (chInfo.connectFlag==1) + value(k).State=mcaConnection{2}; + value(k).MCAMessage=mcaConnection{3}; + else + value(k).State=mcaNoConnection{2}; + value(k).MCAMessage=mcaNoConnection{3}; + end + %value(k).MCAMessage=mocha('statusInfo', mocha('getStatus', h(k))); + value(k).Host =chInfo.hostName; + value(k).Units=pvCtrl.units; +end +if (length(h)==1) + varargout{1} = value; +else + varargout{1} = h; + varargout{2} = value; +end diff --git a/linux-x86_64/2024b/mcaisopen.m b/linux-x86_64/2024b/mcaisopen.m new file mode 100644 index 0000000..19c4249 --- /dev/null +++ b/linux-x86_64/2024b/mcaisopen.m @@ -0,0 +1,20 @@ +function h = mcaisopen(PVNAMESTRING); +%MCAISOPEN - Check if a channel to a PV is open with MCAOPEN +% +% H = MCAISOPEN(PVNAMESTRING) returns an integer handle if open +% and 0 otherwise. If more than one channel is open to the +% same PV, an array of handles is returned. +% +% See also MCAINFO MCASTATE + +if ~ischar(PVNAMESTRING) + error('Argument must be a string') +end + +[handles, names] = mcaopen; +matchfound = find(strcmp(PVNAMESTRING,names)); +if isempty(matchfound) + h = 0; +else + h = handles(matchfound); +end; diff --git a/linux-x86_64/2024b/mcamon.m b/linux-x86_64/2024b/mcamon.m new file mode 100644 index 0000000..16e36fc --- /dev/null +++ b/linux-x86_64/2024b/mcamon.m @@ -0,0 +1,66 @@ +function varargout = mcamon(handle,varargin) +%MCAMON - install or replace monitor on a PV +% +% STS = MCAMON(HANDLE) installs monitor with default callback. +% Default callback updates local copy of the channel data +% every time the data changes on the server. +% This cached data can be read at later time into MATLAB with MCACACHE. +% HANDLE - integer handle to a channel previously opened with MCAOPEN +% Returns 1 on success, 0 on failure +% +% STS = MCAMON(HANDLE,CALLBACKSTRING) installs a monitor and specifies +% a callback string for each. A callback string must be a MATLAB command, +% sequence of commands or a name of a script/function on the MATLAB path. +% It is executed in the 'base' workspace (AFTER the default callback) on +% the next poll of the queue by the MCAMONTIMER command. +% Returns 1 on success, 0 on failure +% +% [HANDLES, CALLBACKSTRINGS]=MCAMON with no arguments returns information +% on all currently installed monitors +% +% Note: Monitors can be installed with MCAMON and cleared with +% MCACLEARMON any number of times. Use MCAMONTIMER to initialise +% the MATLAB timer which polls and processes the outstanding MCA Monitor +% callback queue. +% +% Note: Use of asynchronous features of EPICS (such as monitors) +% with MATLAB requires special care - read MCA notes. +% +% 1.In CA client library (EPICS R3.13.4) asynchronous callbacks run one at a time +% to completion. This means that MATLAB callback string installed with MCAMON +% may not itself contain other MCA functions that call CA library such as MCAGET +% For example MCAMON(H1, 'X=MCAGET(H2);') will not work. +% MCAMON(H1, X='MCACACHE(H2);') is OK since MCACACHE does not use CA library. +% +% See also MCAMONTIMER, MCACACHE, MCAGET, MCACLEARMON. + + +if nargin ==1 + %varargout{1}=mca(100,handle); + monID=mocha('monitor', handle); %return monitorID + status=0; + if (monID > 4095) %1st onid is 0xff (4096) + status=1; + end + varargout{1}=status; +elseif nargin==2 + if ischar(varargin{1}) + %varargout{1} = mca(100,handle,varargin{1}); + monID=mocha('monitor', handle, varargin{1} ) + status=0; + if (monID > 4095) + status=1; + end + else + error('Second argument must be a string'); + end +elseif nargin == 0 + if nargout == 2 + %[varargout{1},varargout{2}]=mca(500); + [varargout{1},varargout{2}]=mocha ('getMonitorHandlesAndActions'); + else + %varargout{1}=mca(500); + varargout{1}=mocha ('getMonitorHandles'); + end +end + diff --git a/linux-x86_64/2024b/mcamonevents.m b/linux-x86_64/2024b/mcamonevents.m new file mode 100644 index 0000000..c3ce922 --- /dev/null +++ b/linux-x86_64/2024b/mcamonevents.m @@ -0,0 +1,25 @@ +function varargout = mcamonevents(varargin) +%MCAMONEVENTS - returns the number of monitor events which have +% occurred for channels since the last call to MCACACHE. +% +% [HANDLES, EVENTCOUNT] = MCAMONEVENTS +% Returns handles and event counts for all open channels +% +% EVENTCOUNT = MCAMONEVENTS(HANDLES) +% Returns event counts for specified channel(s) +% +% See also MCAMON, MCACACHE, MCAGET, MCACLEARMON + +disp('not supported in mocha'); + + +%[handles, count] = mca(510); +%if nargin == 0 +% varargout{1} = handles; +% varargout{2} = count; +%elseif nargin > 0 && isnumeric(varargin{1}) +% for i=1:length(varargin{1}) +% ind(i)=find(handles==varargin{1}(i)); +% end +% varargout{1} = count(ind); +%end diff --git a/linux-x86_64/2024b/mcamontimer.m b/linux-x86_64/2024b/mcamontimer.m new file mode 100644 index 0000000..c26373d --- /dev/null +++ b/linux-x86_64/2024b/mcamontimer.m @@ -0,0 +1,64 @@ +function varargout = mcamontimer(varargin) +%MCAMONTIMER - Controls the initialisation and termination of the MATLAB +% timer used to poll the MCA monitor command queue. +% +% Started = mcamontimer - returns 1 if monitor polling has been started +% returns 0 if monitor polling has not been started +% +% mcamontimer('start') - starts the timer polling every 0.1 seconds +% mcamontimer('stop') - stops the timer +% +% Notes: +% (1) If monitors are installed using mcamon but mcaTimer has not been +% started, the monitor events will queue up indefinitely. There is +% no limit to the size of the queue, so eventually you will +% run out of memory and crash. +% (2) A polling period of 0.1 seconds is used. This may be varied if +% desired by modifying the 'Period' argument in the definition of +% mcaTimer. +% (3) Call mcamontimer('start') once. +% +% See also MCAMON, MCAMONEVENTS, MCACACHE, MCACLEARMON +% +persistent mcaTimer TimerStarted; + +%mocha('test') + +if (nargin == 0) + if (TimerStarted) + varargout{1} = 1; + else + varargout{1} = 0; + end +elseif (nargin == 1) + switch varargin{1} + case 'start' + if (TimerStarted) + error('MCA monitor polling is already started.'); + end + mlock; + %mcaTimer = timer('TimerFcn', 'mca(600)', 'Period', 0.1, 'ExecutionMode', 'fixedSpacing'); + + + + mcaTimer = timer('TimerFcn', 'mocha(402)', 'Period', 10.1, 'ExecutionMode', 'fixedSpacing'); + %%mcaTimer.TimerFcn= {@mocha, 'monitorflushevent'}; + start (mcaTimer); + TimerStarted = 1; + case 'stop' + if (TimerStarted) + munlock; + stop (mcaTimer); + clear mcaTimer; + TimerStarted = 0; + + + else + error('MCA monitor polling has not been started.'); + end + otherwise + error('Invalid parameter specified for mcamontimer. Use ''start'' or ''stop''.') + end +else + error('Invalid number of arguments in mcamontimer.') +end diff --git a/linux-x86_64/2024b/mcaopen.m b/linux-x86_64/2024b/mcaopen.m new file mode 100644 index 0000000..fa1013c --- /dev/null +++ b/linux-x86_64/2024b/mcaopen.m @@ -0,0 +1,61 @@ +function varargout = mcaopen(varargin); +%MCAOPEN - open a Channel Access connection to an EPICS Process Variable +% +% H = MCAOPEN(PVNAME); +% If successful H is a unique nonzero integer handle associated with this PV. +% Returned handle is 0 if a connection could not be established +% +% [H1, ... ,Hn] = MCAOPEN(PVNAME1, ... ,PVNAMEn); +% Is equivalent to but more efficient than multiple single-argument calls +% H1 = MCAOPEN(PVNAME1); +% ... +% Hn = MCAOPEN(PVNAMEn); +% +% HANDLES = MCAOPEN(NAMES) is convenient when working with long lists of PV names +% HANDLES is a numeric array of assigned handles +% NAMES is a cell array of strings with PV names +% +% [HANDLES, NAMES] = MCAOPEN with no arguments returns a list of PV Names for all open connections. +% HANDLES is a numeric array of handles +% NAMES is a cell array of strings with PV names +% +% Note: +% When done, one should probably use MCACLOSE on the handle. +% When you use the same channel again "later", you might keep it open. +% See MCACHECKOPEN for a lazy person's bookkeeping helper. +% +% See also: MCACHECKOPEN, MCAISOPEN, MCACLOSE + +if nargin>1 && nargin ~= nargout + error('Number of outputs must match the number of inputs') +end + + +if nargin==0 + [varargout{1} varargout{2}] = mocha('getHandles'); %mca(3); + +elseif iscellstr(varargin) && nargin ==1 + varargout{1} = mocha('open', varargin{1} ); + +elseif iscellstr(varargin{1}) && nargin==1 + if length(varargin{1}) > 1 + mocha ('openPrepare'); + varargout{1} = mocha('open', varargin{1} ); + mocha ('openNow') + else + varargout{1} = mocha('open', varargin{1} ); % mca(2,varargin{1}); + end + +elseif iscellstr(varargin) + mocha('openPrepare'); + %[varargout{1:nargin}] = + h1=mocha('openArray',{varargin{:}}) %mca(1,varargin{:}); + for i = 1:length(h1) + [varargout{i}] = h1(i); + end + mocha('openNow'); +else + error('All arguments must be strings') +end + + diff --git a/linux-x86_64/2024b/mcapoll.m b/linux-x86_64/2024b/mcapoll.m new file mode 100644 index 0000000..2cbfbc7 --- /dev/null +++ b/linux-x86_64/2024b/mcapoll.m @@ -0,0 +1,4 @@ +function mcapoll() +%MCAPOLL - poll channel access... +%mca(30) +mocha('capoll') diff --git a/linux-x86_64/2024b/mcaprec.m b/linux-x86_64/2024b/mcaprec.m new file mode 100644 index 0000000..99e0961 --- /dev/null +++ b/linux-x86_64/2024b/mcaprec.m @@ -0,0 +1,35 @@ +function varargout = mcaprec(varargin) +%MCAPREC - read precision from PV's +% +% VALUES = MCAPREC(HANDLE) returns the precision field of a channel as a double +% +% The function does not handle arrays of PV handles, but only a single PV at at time. +% +% +% Error handling: +% An empty cell string array will be returned if the PV type is not ENUM. +% A matlab exception will be thrown when the PV handle is invalid, +% i.e. not the result of a successful MCAOPEN. +% Furthermore, an error can result from a 'get' timeout, +% configurable via MCATIMEOUT. +% In addition, an error can result from a network disconnect. +% In principle, one can check beforehand via MCASTATE, but since +% a disconnect might happen just between the successful MCASTATE call +% and the following MCAGET, the only safe thing might be to surround +% MCAGET calls with TRY....CATCH. +% +% See also TRY, CATCH, MCASTATE, MCATIMEOUT, MCAPUT +if nargin<1 + error('No arguments were specified in mcaget') +elseif nargin==1 + if length(varargin{1})>1 + error('Only single PV can be handled at a time') + else + %varargout{1} = mca(42,varargin{1}); + pvCtrl = mocha('getCtrl', varargin{1}); + varargout{1} =pvCtrl.precision(); + end +elseif nargin>1 + error('Only single PV can be handled at a time') +end + diff --git a/linux-x86_64/2024b/mcaput.m b/linux-x86_64/2024b/mcaput.m new file mode 100644 index 0000000..a9e0948 --- /dev/null +++ b/linux-x86_64/2024b/mcaput.m @@ -0,0 +1,109 @@ +function sts = mcaput(varargin) +%MCAPUT - Write values to EPICS Process Variables +% +% MCAPUT(HANDLE1, VALUE1) - one handle, one value +% MCAPUT(HANDLE1, VALUE1, ... , HANDLE_N, VALUE_N) - handles and values in pairs +% +% EPICS STRING values are passed as MATLAB strings. For example: +% >> mcaput(H, 'MATLAB') +% >> mcaput(H1, 'MATLAB', H2, 'EPICS') +% or cell arrays of strings. +% +% MCAPUT(HANDLES_CELL_ARRAY, VALUES_CELL_ARRAY) - arguments are grouped +% in cell array of integer handles and a cell array of values +% of equal length. +% +% Returns an array of status values: 1 success, 0 failure, -1 timeout +% +% MCAPUT is implemented as a call to the ca_put_array_callback +% function in CA client library. +% MCAPUT returns 1 or 0 if we get an OK respectively error status within +% the timeout, or -1 if we don't get any response within the timeout. +% +% Note: +% The special case of MCAPUT([PV, PV, ...], [SCALAR, SCALAR, ...]) +% will simply write the scalar values to the PVs without waiting for the +% callback. +% +% See also MCAGET, MCATIMEOUT. + +if nargin==2 + if iscell(varargin{1}) && iscell(varargin{2}) + % {pv, pv, pv, ...}, {value, value, value, ...} + if length(varargin{1}) ~= length(varargin{2}) + error('Cell array of MCA handles and cell array of values must be the same length') + end + HANDLES = varargin{1}; VALUES = varargin{2}; + ARGS = reshape([HANDLES(:)';VALUES(:)'],1,2*length(varargin{1})); + %sts = mca(70,ARGS{:}); + mocha('setputwait',HANDLES); + [gsts,sts]=mocha('setScalarArray', HANDLES, VALUES); + elseif isnumeric(varargin{1}) + if length(varargin{1})>1 + if length(varargin{1}) ~= length(varargin{2}) + error('Array of handles and array of values must be the same length'); + end + % [pv, pv, pv, ...], [value, value, value, ...] + %sts = mca(80,varargin{1},varargin{2}); + mocha('setputwait', varargin{1}); + [gsts,sts]=mocha('setScalarArray', varargin{1},varargin{2}); + else + ARGS = varargin; + % (pv, value) + if (isnumeric(ARGS{2}(1))) + %if (isnumeric(ARGS(2))) + %sts = mca(70,ARGS{:}); + mocha('setputwait',ARGS{1}); + sts = mocha('set',ARGS(1), ARGS(2)); + else + chInfo=mocha('getInfo', varargin{1}); + if(strcmp(chInfo.dataType,'DBR_ENUM')&&~isnumeric(varargin{2})) + %if(strcmp(mca(43,varargin{1}),'ENUM')&&~isnumeric(varargin{2})) + pvCtrl=mocha('getCtrlCache', varargin{1}); + enumvalues= pvCtrl.enumStrings; %mca(40,varargin{1}); + %enumvalues=mca(40,varargin{1}); + found = 0; + for ind = 1:numel(enumvalues) + if(strcmp(ARGS(2),enumvalues(ind))) + valueToPut=ind-1; + found=1; + end + end + if(found) + ARGS{2}=valueToPut; + mocha('setputwait',ARGS(1)); + sts = mocha('set',ARGS(1), ARGS(2)); % mca(70,ARGS{:}); + else + strings = sprintf(' "%s" ',enumvalues{:}); + error('mcaput:enumCheck','Invalid value for this channel. Try one of: [%s]',strings); + end + else + %sts = mca(70,ARGS{:}); + mocha('setputwait',ARGS(1)); + sts = mocha('set',ARGS(1), ARGS(2)); + end + end + end + else + error('Invalid mcaput args, need PV, VALUE'); + end +elseif mod(nargin,2) == 0 + % 'pv, value, pv, value, ...' + %sts = mca(70,varargin{:}); + + + j=uint16(0); + for i=1:2:nargin + j=j+1; + handles(j)=varargin{i}; + values{j}=varargin{i+1}; + end + + + + mocha('setputnowait',handles); + [gsts,sts]=mocha('setMany', handles, values{1:j}); + +else + error('Incorrect number of inputs, need a sequence of PV, VALUE') +end diff --git a/linux-x86_64/2024b/mcaputnowait.m b/linux-x86_64/2024b/mcaputnowait.m new file mode 100644 index 0000000..6aaee19 --- /dev/null +++ b/linux-x86_64/2024b/mcaputnowait.m @@ -0,0 +1,118 @@ +function sts = mcaputnowait(varargin) +%MCAPUT - Write values to EPICS Process Variables +% +% MCAPUT(HANDLE1, VALUE1) - one handle, one value +% MCAPUT(HANDLE1, VALUE1, ... , HANDLE_N, VALUE_N) - handles and values in pairs +% +% EPICS STRING values are passed as MATLAB strings. For example: +% >> mcaput(H, 'MATLAB') +% >> mcaput(H1, 'MATLAB', H2, 'EPICS') +% or cell arrays of strings. +% +% MCAPUT(HANDLES_CELL_ARRAY, VALUES_CELL_ARRAY) - arguments are grouped +% in cell array of integer handles and a cell array of values +% of equal length. +% +% Returns an array of status values: 1 success, 0 failure, -1 timeout +% +% MCAPUT is implemented as a call to the ca_put_array_callback +% function in CA client library. +% MCAPUT returns 1 or 0 if we get an OK respectively error status within +% the timeout, or -1 if we don't get any response within the timeout. +% +% Note: +% The special case of MCAPUT([PV, PV, ...], [SCALAR, SCALAR, ...]) +% will simply write the scalar values to the PVs without waiting for the +% callback. +% +% See also MCAGET, MCATIMEOUT. + +if nargin==2 + if iscell(varargin{1}) && iscell(varargin{2}) + % {pv, pv, pv, ...}, {value, value, value, ...} + if length(varargin{1}) ~= length(varargin{2}) + error('Cell array of MCA handles and cell array of values must be the same length') + end + HANDLES = cell2mat(varargin{1}); VALUES = cell2mat(varargin{2}); + disp('first call to mca 80') + %sts = mca(80,HANDLES,VALUES); + mocha('setputnowait',HANDLES); + [gsts,sts]=mocha('setScalarArray', HANDLES, VALUES); + elseif isnumeric(varargin{1}) + if length(varargin{1})>1 + if length(varargin{1}) ~= length(varargin{2}) + error('Array of handles and array of values must be the same length'); + end + % [pv, pv, pv, ...], [value, value, value, ...] + disp('call mca 80') + %sts = mca(80,varargin{1},varargin{2}); + mocha('setputnowait', varargin{1}); + [gsts,sts]=mocha('setScalarArray', varargin{1},varargin{2}); + else + ARGS = varargin; + %a=ARGS{1}; + %b=ARGS{2}; + + % (pv, value) + if (isnumeric(ARGS{2}(1))) %(ARGS(2))) + %sts = mca(80,ARGS{:}); + mocha('setputnowait',ARGS{1}); + sts = mocha('set',ARGS(1), ARGS(2)); + else + chInfo=mocha('getInfo', varargin{1}); + %if(strcmp(mca(43,varargin{1}),'ENUM')&&~isnumeric(varargin{2})) + if(strcmp(chInfo.dataType,'DBR_ENUM')&&~isnumeric(varargin{2})) + pvCtrl=mocha('getCtrlCache', varargin{1}); + enumvalues= pvCtrl.enumStrings; %mca(40,varargin{1}); + + found = 0; + for ind = 1:numel(enumvalues) + if(strcmp(ARGS(2),enumvalues(ind))) + valueToPut=ind-1; + found=1; + end + end + if(found) + ARGS{2}=valueToPut; + mocha('setputnowait',ARGS(1)); + sts = mocha('set',ARGS(1), ARGS(2)); % mca(70,ARGS{:}); + else + strings = sprintf(' "%s" ',enumvalues{:}); + error('mcaput:enumCheck','Invalid value for this channel. Try one of: [%s]',strings); + end + else + mocha('setputnowait',ARGS(1)); + sts = mocha('set',ARGS(1), ARGS(2)); %mca(80,ARGS{:}); + + end + end + end + else + error('Invalid mcaput args, need PV, VALUE'); + end +elseif mod(nargin,2) == 0 + % 'pv, value, pv, value, ...' + % sts = mca(80,handles,values); + %for i=1:nargin + %params(i)=varargin{i}; + %end + %nargin; + %data=reshape(params,2,nargin/2); + %handles=data(1,:); + %values=data(2,:); + j=uint16(0); + for i=1:2:nargin + j=j+1; + handles(j)=varargin{i}; + values{j}=varargin{i+1}; + end + + disp(handles) + disp(values) + + mocha('setputnowait',handles); + [gsts,sts]=mocha('setMany', handles, values{1:j}); + %disp('pv,val,pv,val') +else + error('Incorrect number of inputs, need a sequence of PV, VALUE') +end diff --git a/linux-x86_64/2024b/mcastate.m b/linux-x86_64/2024b/mcastate.m new file mode 100644 index 0000000..fbb0d6c --- /dev/null +++ b/linux-x86_64/2024b/mcastate.m @@ -0,0 +1,46 @@ +function varargout = mcastate(varargin); +%MCASTATE - returns an array of connection states for open channels +% MCASTATE is used as diagnostics prior to issuing other +% MCA commands such as MCAGET, MCAPUT and MCAMON +% +% STATES = MCASTATE(H1,H2,...,HN) returns the states of +% the specified channels previously opened with MCAOPEN. +% STATES = an array of the states of the channels listed in the HANDLES +% array +% +% [HANDLES, STATES] = MCASTATE is an array of states of all +% currently open channels. +% HANDLES = an array of all the currently open channels +% STATES = an array of the states of the channels listed in the HANDLES +% array +% +% Possible values +% 1 - Connected: MCAGET, MCAPUT and MCAMON are valid +% 0 - Disconnected: MCAGET, MCAPUT and MCAMON will return invalid +% data or fail. This may be due to a server/network problem +% +% See also MCAINFO, MCAOPEN, MCACLOSE. + +%if nargin > 0 +% varargout{1} = mca(13,varargin{:}); +%else +% [varargout{1}, varargout{2}] = mca(12); +%end + + +if nargin > 0 + %varargout{1} = mca(13,varargin{:}); + for k = 1:nargin + if mocha('isConnected', varargin{k}) == true + isConnected(k) = uint16(1); + else + isConnected(k) = uint16(0); + end + end + varargout{1} = isConnected; +else + [h,pv,state] = mocha('getHandleStates'); + %[varargout{1}, varargout{2}] = mca(12); + varargout{1} = h; + varargout{2} = state; +end diff --git a/linux-x86_64/2024b/mcatime.m b/linux-x86_64/2024b/mcatime.m new file mode 100644 index 0000000..215934b --- /dev/null +++ b/linux-x86_64/2024b/mcatime.m @@ -0,0 +1,44 @@ +function varargout = mcatime(varargin) +%MCATIME - read timestamps for PVs previously read with MCAGET or MCAMON +% +% The timestamp is returned as a MATLAB serial date number suitable +% for use in the DATESTR function. +% +% The original time stamp is in the UTC timezone, +% but since Matlab doesn't handle timezones in datenum/datastr, +% it's converted to the 'local' timezone, so that +% datestr(mcatime(pv)) +% should give a time that is close to the wall clock +% for channels that changed recently. +% +% VALUE = MCATIME(HANDLE) +% returns the timestamp of a PV specified by integer HANDLE. +% +% [VALUE1, ... VALUEN] = MCATIME(HANDLE1, ... , HANDLEN) +% returns timestamps of multiple PVs of any type and length +% Number of outputs must match the number of inputs +% +% See also MCAGET, MCAMON. +% +for i=1:nargin + + % We get y/m/d H:M:S plus nanosecs... + %pieces = mca(60,varargin{i}); + % but datenum doesn't handle nanosecs + %varargout{i} = datenum(pieces(1:6)); + timestamp=mocha('getTimeStamp',varargin{i}); + timestamp=double(timestamp); + + timestamp(6)=timestamp(6)+timestamp(7)/double(1000000000); + %value.time(1)=double(timestamp(1)); + %value.time(2)=(timestamp(2)); + %value.time(3)=(timestamp(3)); + %value.time(4)=(timestamp(4)); + %value.time(5)=(timestamp(5)); + + %varargout{i}(1:5)=value.time(1:5);= + %varargout{i}(6)=double(timestamp6); + varargout{i}=timestamp(1:6); + %format longG; +end + diff --git a/linux-x86_64/2024b/mcatimeout.m b/linux-x86_64/2024b/mcatimeout.m new file mode 100644 index 0000000..e51dcc5 --- /dev/null +++ b/linux-x86_64/2024b/mcatimeout.m @@ -0,0 +1,64 @@ +function varargout = mcatimeout(varargin) +%MCATIMEOUT - set or display MCA timeout setings +% +% MCATIMEOUT('open', t1) +% 'open' option sets the internal variable MCA_SEARCH_TIMEOUT to t1 (sec) +% +% MCATIMEOUT('get', t1) +% 'get' option sets the internal variable MCA_GET_TIMEOUT to t1 (sec) +% +% MCATIMEOUT('put', t1) +% 'put' option sets the internal variable MCA_PUT_TIMEOUT to t1 (sec) +% +% MCATIMEOUT('default') sets the default values +% MCA_SEARCH_TIMEOUT = 1.0 (sec) +% MCA_GET_TIMEOUT = 5.0 (sec) +% MCA_PUT_TIMEOUT = 0.01 (sec) +% +% TIMEOUTS = MCATIMEOUT with no arguments returns a vector of currently set timeouts +% in the format [MCA_SEARCH_TIMEOUT MCA_GET_TIMEOUT MCA_PUT_TIMEOUT] +% +% Notes: +% See also: MCA.cpp +% +switch nargin + case 0 + a=mocha('getTimeout'); + %a(1) Put %a(2)Get + b=mocha('getOpenWaitTime'); + AB=[b(1); a(2); a(1)]; %search, get, put + varargout{1} = AB(1:3); %mca(1000); + case 1 + if strcmp(varargin{1}, 'default') + a=mocha('setTimeOutDefault'); + b=mocha('openWaitWithTimeDefault'); + AB=[b(1); a(2); a(1)]; %search, get, put + varargout{1} = AB(1:3); %mca(1004); + else + error ('Invalid command option.') + end + case 2 + if strcmp(varargin{1}, 'open') + if ~isnumeric(varargin{2}) || varargin{2} <= 0 + error('Second argument must be numeric, positive seconds'); + end + mocha('openWaitWithTime',varargin{2}); + %mca(1001,varargin{2}); + elseif strcmp(varargin{1}, 'get') + if ~isnumeric(varargin{2}) || varargin{2} <= 0 + error('Second argument must be numeric, positive seconds'); + end + mocha('setTimeoutGet',varargin{2}); + %mca(1002,varargin{2}); + elseif strcmp(varargin{1}, 'put') + if ~isnumeric(varargin{2}) || varargin{2} <= 0 + error('Second argument must be numeric, positive seconds'); + end + mocha('setTimeoutPut',varargin{2}); + %mca(1003,varargin{2}); + else + error('Invalid command option.') + end + otherwise + error ('Invalid number of arguments.') +end diff --git a/linux-x86_64/2024b/mcaunlock.m b/linux-x86_64/2024b/mcaunlock.m new file mode 100644 index 0000000..3bcdeeb --- /dev/null +++ b/linux-x86_64/2024b/mcaunlock.m @@ -0,0 +1,11 @@ +function mcaunlock; +%MCAUNLOCK - unlocks the MCAMAIN mex-file +% .. so that it can be cleared from memory with CLEAR +% +% MCAMAIN starts in a locked state +% to protect from it from being +% accidentally cleared and +% loosing channel access connections. +%mca(0); +mocha('mexUnlock'); +%disp('mca mex-file is now UNLOCKED'); diff --git a/linux-x86_64/2024b/mcaversion.m b/linux-x86_64/2024b/mcaversion.m new file mode 100644 index 0000000..ee06a6b --- /dev/null +++ b/linux-x86_64/2024b/mcaversion.m @@ -0,0 +1,8 @@ +function ver = mcaversion() +%MCAVERSION - get version info +% ver = mcaversion() +% +% returns the mca version as a string + +%ver = mca(-1); +ver = mocha('version'); diff --git a/linux-x86_64/2024b/monitorAction.m b/linux-x86_64/2024b/monitorAction.m new file mode 100644 index 0000000..28a261e --- /dev/null +++ b/linux-x86_64/2024b/monitorAction.m @@ -0,0 +1,16 @@ +function varargout = monActionLocal(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)]) diff --git a/linux-x86_64/2024b/pvtable.m b/linux-x86_64/2024b/pvtable.m new file mode 100755 index 0000000..426a015 --- /dev/null +++ b/linux-x86_64/2024b/pvtable.m @@ -0,0 +1,48 @@ +function pvt = pvtable() +% +% pvt=pvtable() +% returns a table displaying all pvs and their status +% +[hpv,pvn,state] = mocha('getHandleStates'); + +pvt=[]; +if (isempty(hpv)) + disp('THERE ARE NO CHANNELS!'); + return; +end + +%If monitor then uses cache value +mocha('getAsyn', hpv); +mocha('sendNow'); %otherwise getPVCache will do the send! +dstruct = mocha('getPVCache', hpv); + +%If NaN then following warning given from struct2table: +%Warning: Out of range or non-integer values truncated during +%conversion to character +% +t=struct2table(dstruct); + +for n=1:length(hpv) + s1(n).handle=hpv(n); + s1(n).pv=pvn(n); + s1(n).cs=state(n); + s1(n).nmon=mocha('getNoMonitors', hpv(n)); +end + +t1=struct2table(s1); + +if (string(class(t.val)) == string('char')) + t.val=string(t.val); +end + +pvt=table(t1.handle,t1.pv, t.val, t.status, t1.cs, t1.nmon); +pvt.Properties.VariableNames={'h','pv', 'val', 'stat','c', 'm'}; +%tNew.Properties.VariableNames{'Var1'}= 'handle'; +%tNew.Properties.VariableNames{'Var2'}= 'pv'; +%tNew.Properties.VariableNames{'Var3'}= 'val'; + + +%2017a +%setColHeading(tNew, 1, 'handle'); +%setColHeading(tNew, 2, 'pv'); +%setColHeading(tNew, 3, 'val'); diff --git a/linux-x86_64/2024b/test.xml b/linux-x86_64/2024b/test.xml new file mode 100644 index 0000000..f951bbb --- /dev/null +++ b/linux-x86_64/2024b/test.xml @@ -0,0 +1,18 @@ + + + + + ARIDI-BPM-01LE:X-AVG + + ARIDI-BPM-01LE:Y-AVG + + + diff --git a/linux-x86_64/2025a/macchinettaSwitch.o b/linux-x86_64/2025a/macchinettaSwitch.o new file mode 100644 index 0000000..b0a8cd8 Binary files /dev/null and b/linux-x86_64/2025a/macchinettaSwitch.o differ diff --git a/macchinettaSwitch.cpp b/macchinettaSwitch.cpp index 08aa0cb..55d3708 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.21.0 : 12 July 2024; Contact: Felix Armborst"); + plhs[0]=mxCreateString((char *) "mocha-1.22.0 : 6 October 2025; Contact: Felix.Armborst@psi.ch"); break; case SHOW: diff --git a/makefile_rel_1.22-gcc-10.4.0 b/makefile_rel_1.22-gcc-10.4.0 new file mode 100644 index 0000000..afbecf4 --- /dev/null +++ b/makefile_rel_1.22-gcc-10.4.0 @@ -0,0 +1,105 @@ +# +# 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.22.0-gcc-10.4.0 +#CAFE version to link to +CAFE_VERSION=cafe-1.22.0-gcc-10.4.0 + +EPICS_BASE=${EPICS}/base-7.0.9 +#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) + cp example.m $(OBJ_DIR) + cp scripts/*.m $(OBJ_DIR) + cp scripts/test.xml $(OBJ_DIR) + + +$(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/*.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/makefile_rel_1.22-gcc-10.4.0.sh b/makefile_rel_1.22-gcc-10.4.0.sh new file mode 100644 index 0000000..c40aa6e --- /dev/null +++ b/makefile_rel_1.22-gcc-10.4.0.sh @@ -0,0 +1,5 @@ +module unload gcc +module load gcc/10.4.0 +echo "$1" +action=$1 +make -f makefile_rel_1.22-gcc-10.4.0 -s $action