I think you can do this with an aCalcout record with no C code.
Hi,
I want to perform some operation using elements in 3 EPICS records, where one record is a waveform and other two are subArrays. (As indicated below)
========================= Waveform record ================================
record(waveform, "$(acc):$(sys)_$(group):acq2106_current")
{
field(INP, {pva:{pv:"acq2106_347:1:AI:WF:17", "proc": "CP"}})
field(FTVL, "DOUBLE")
field(NELM, "4096")
field(SCAN, "1 second")
}
======================== subArrary record 1 ==============================
record(subArray, "$(acc):$(sys)_$(group):acq2106_calibvalue_eslo") {
field(DESC, "Extracted subset of WAVE")
field(INP, {pva:{pv:"acq2106_347:1:AI:CAL:ESLO", "proc":"CP"}})
field(FTVL, "DOUBLE")
field(MALM, "10")
field(NELM, "1")
field(INDX, "17")
field(SCAN, "1 second")
}
==================== subArray record 2 ================================
record(subArray, "$(acc):$(sys)_$(group):acq2106_calibvalue_eoff") {
field(DESC, "Extracted subset of WAVE")
field(INP, {pva:{pv:"acq2106_347:1:AI:CAL:EOFF", "proc":"CP"}})
field(FTVL, "DOUBLE")
field(MALM, "10") # If set this to 1, does not return the expected outcome
field(NELM, "1")
field(INDX, "17")
field(SCAN, "1 second")
}
===================================================================
Here I am trying to loop over every element of the wave form and multiply each element by the single element of the subarray 1 and add the only element in the subarray 2 to the result (subarray 1 and subarray 2 have only one element)
So to achieve this goal, I created aSub record (pasted below) and inside that I called the function named calibWave.c (pasted below).
========================== calibWave.c ==============================
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <stdio.h>
#include <math.h>
#include <ncurses.h>
#include "dbDefs.h"
#include "registryFunction.h"
#include "epicsExport.h"
#include "epicsExit.h"
#include "epicsThread.h"
#include "iocsh.h"
#include "aSubRecord.h"
static double calibWave(aSubRecord *prec)
{
double *in = (double*)prec->a;
double *out = (double*)prec->vala;
double eslo = *(double*)prec->b;
double eoff = *(double*)prec->c;
int n = prec->nea;
for(int i = 0; i < n; i++) {
out[i] = in[i] * eslo + eoff;
}
return 0;
}
EpicsRegisterFunction(calibWave);
====================================================================
==================== aSub record for the calculated waveform ===============
record(aSub, "$(acc):$(sys)_$(group):acq2106_calib_current") {
field(INPA, "$(acc):$(sys)_$(group):acq2106_current CPP")
field(INPB, "$(acc):$(sys)_$(group):acq2106_calibvalue_eslo CPP")
field(INPC, "$(acc):$(sys)_$(group):acq2106_calibvalue_eoff CPP")
field(FTA, "DOUBLE")
field(FTB, "DOUBLE")
field(FTC, "DOUBLE")
field(NOA, "4096")
field(NOB, "1")
field(NOC, "1")
field(FTVA, "DOUBLE")
field(NOVA, "4096")
field(SNAM, "calibWave")
field(SCAN, "1 second")
field(PREC, 5)
}
===================================================================
But this aSub only returns a single number instead of a waveform (as indicated below)
=================== pvxget for asub record ==========================
PIP2:CTRL_MPS:acq2106_calib_current
value int32_t = 4090
alarm.severity int32_t = 0
alarm.status int32_t = 0
alarm.message string = ""
timeStamp.secondsPastEpoch int64_t = 1775158362
timeStamp.nanoseconds int32_t = 7852163
timeStamp.userTag int32_t = 0
display.limitLow int32_t = 0
display.limitHigh int32_t = 0
display.description string = ""
display.units string = ""
display.form.index int32_t = 0
display.form.choices string[] = {7}["Default", "String", "Binary", "Decimal", "Hex", "Exponential", "Engineering"]
control.limitLow int32_t = -2147483648
control.limitHigh int32_t = 2147483647
valueAlarm.lowAlarmLimit int32_t = 0
valueAlarm.lowWarningLimit int32_t = 0
valueAlarm.highWarningLimit int32_t = 0
valueAlarm.highAlarmLimit int32_t = 0
====================================================================
I am not sure, where the problem happens (either calibWave.C function or aSub record ) or not sure whether aSub record is the best solution to achieve this goal.
Any help to debug this is highly appreciated.
============================================== Additional information ==============================================================
I am not 100% the way I created the custom calibWave. Function. Following are the steps, I followed.
-
First I created a .dbd file named waveCalib.dbd inside "src" directory and added the function name
************************************** content of waveCalib.dbd ********************************************
Function(calibWave)
***********************************************************************************************************
-
Modified Make file at "src" directory by adding the commented lines
******************************************** Makefile content at src directory *******************************
TOP=../..
include $(TOP)/configure/CONFIG
#----------------------------------------
# ADD MACRO DEFINITIONS AFTER THIS LINE
#=============================
#=============================
# Build the IOC application
PROD_IOC = XRM
# XRM.dbd will be created and installed
DBD += XRM.dbd
# XRM.dbd will be made up from these files:
XRM_DBD += base.dbd
# modified menuScan.dbd to include FNAL scan rates
XRM_DBD += menuScan.dbd
# waveCalib.dbd including the calibWave.c function
XRM_DBD += waveCalib.dbd // ***********************************Addition
# Include dbd files from all support applications:
XRM_DBD += pvxsIoc.dbd
XRM_DBD += iocAdmin.dbd
XRM_DBD += aliveRecord.dbd
XRM_DBD += sseqRecord.dbd
XRM_DBD += sscanSupport.dbd
XRM_DBD += acnetPV.dbd
XRM_DBD += tcast.dbd
XRM_DBD += reccaster.dbd
XRM_DBD += asSupport.dbd
XRM_DBD += caPutJsonLog.dbd
XRM_DBD += sCalcoutRecord.dbd
XRM_DBD += calcSupport.dbd
XRM_DBD += aCalcoutRecord.dbd
# Add all the support libraries needed by this IOC
XRM_LIBS += devIocStats
XRM_LIBS += alive
XRM_LIBS += acnetPV
XRM_LIBS += calc
XRM_LIBS += pv seq
XRM_LIBS += sscan
XRM_LIBS += tcast
XRM_LIBS += reccaster
XRM_LIBS += autosave
XRM_LIBS += caPutLog
XRM_LIBS += pvxsIoc pvxs
# XRM_registerRecordDeviceDriver.cpp derives from XRM.dbd
XRM_SRCS += XRM_registerRecordDeviceDriver.cpp
XRM_SRCS += CopyArray.c
XRM_SRCS += calibWave.c // *************************** Addition
# Build the main IOC entry point on workstation OSs.
XRM_SRCS_DEFAULT += XRMMain.cpp
XRM_SRCS_vxWorks += -nil-
# Add header files:
#USR_INCLUDES += -I/usr/include
#
# Finally link to the EPICS Base libraries
XRM_LIBS += $(EPICS_BASE_IOC_LIBS)
#===========================
include $(TOP)/configure/RULES
#----------------------------------------
# ADD RULES AFTER THIS LINE
USR_CXXFLAGS_DEFAULT += -fno-operator-names -pedantic
USR_CXXFLAGS += -W -Wall
**************************************************************************************************************
After compilng the project successfully, I checked the XRM.dbd file at .dbd directory and I can that it contains the line
Function(calibWave)
================================================== End of Additional Information ====================
Thanks
Varuna Meddage