V4 Design: RecordCommon Support
EPICS V4: RecordCommonSupport - October 04 2005
Overview
This document describes the implementation of the record support for RecordCommon, i.e. the set of fields associated with every record type.
For V4 dbCommon.dbd and RecordCommon.dbd replace the V3 dbCommon.dbd. dbCommon.dbd define widely used definitions and RecordCommon.dbd defines the fields that are common to all record types.
This document describes the following:
- The code automatically generated from dbCommon.dbd and RecordCommon.dbd
- A proposed implementation of RecordCommonSupport.
This document requires that the reader be familiar with:
- V3 iocCore
- V4 Design: Record Processing
- V4 Design: dbdInterfaces
- V4 Design: Runtime interfaces
- V4 Design: RecordCommon
Java is used as the example code for two reasons:
- For V4 iocCore it is intended that both C++ and Java implementations will be provided. Since V3 is only implemented in C and C++ the Java implemention of V4 is described first to make sure that the interfaces defined in dbdInterfaces will work for Java.
- Java provides facilities that make it easy to handle strings, arrays, and structures.
An implementaion of RecordCommonSupport is presented for two reasons:
- It demonstrates how to implement code that uses or implements the interfaces described in "V4 Design: dbdInterfaces" and "V4 Design: Runtime interfaces".
- It helps refine the interfaces described in them
dbCommon.dbd
See the description of dbCommon.dbd in "V4 Design: RecordCommon"
Link support must register support for each of the link definitions.
From dbCommon.dbd the following class implementations are generated:
- For the link structures:
- MonitorLink, MonitorLinkData, and MonitorLinkSupport
- InputLink, InputLinkData, and InputLinkSupport
- OutputLink, OutputLinkData, and OutputLinkSupport
- ProcessLink, ProcessLinkData, and ProcessLinkSupport
- For TimeStamp
- TimeStamp, TimeStampData, and TimeStampSupport
- For Scan
- Scan, ScanData, and ScanSupport
See "V4 Design: Runtime interfaces" for an example of how these classes are defined.
RecordCommon.dbd
See the description of RecordCommon.dbd in "V4 Design: RecordCommon"
RecordCommon.dbd must be part of every record.
Implementations of Disable, DisableData, and DisableDataSupport are automatically generated.
An implementations of RecordCommon is also generated. See "V4 Design: Runtime interfaces" for an example of the generated classes.
RecordCommonSupport.java
Overview
This section describes the java implementation of RecordCommon functionality. This code handles processing of the following fields of RecordCommon:
- disable
- Decides if the record is disabled.
- alarmStatus and alarmSeverity
- The only way to change alarmStatus and alarmSeverity is via interface Common, which is implemented by RecordCommonSupport.
- processLink
- This is an array of process links, which replace the V3 FLNK
The following subsection describes the code for RecordCommonSupport.java. The remaining subsections describes the code for additional classes that are part of the implementation.
RecordCommonSupport.java
interface Common { boolean setSeverity(AlarmSeverity severity, string status); } public class RecordCommonSupport implements RecordSupport, Common { private RecordInstance instance; private Input input; private Output output; // The following are for implementing Common.setSeverity private short severity; private String status; private DbfMenu alarmSeverity; private DbfString alarmStatus; private boolean modifyingAlarm; // Constructor public RecordCommonSupport(RecordInstance instance) { this.instance = instance; } // Beginning of RecordSupport public destroy() {} // destroy not needed for Java public initialize(int pass) { if(pass==0) return; input = new Input(instance); output = new Output(instance); alarmSeverity = instance.getField("alarmSeverity"); alarmStatus = instance.getField("alarmStatus"); severity = alarmSeverity.get(); alarmStatus.get(status); } public ProcessReturn process(processState state,Callback callback) { if(state==processCancel) { input.process(state,callback); output.process(state,callback); return processDone; } if(state==processStart) { ProcessReturn result = input.process(state,callback); if(result!=processDone) return result; } if(state==processFinish) { ProcessReturn result = output.process(state,callback); if(result!=processDone) return result; } return output.process(state,callback) } public boolean special(boolean after,Dbf[] field) { int nlevels = field.length; assert(nlevels>0); if(index==alarmStatusIndex || index==alarmSeverityIndex) { if(!alarm.modifyingAlarm) return false; return true; } if(!after) return; switch(index) { case disableIndex: { if(nlevels==1) { input = new Input(instance); } else { input.special(instance,Dbf[1]); } break; } case processLinkIndex : output = new Output(instance); break; default: printf("Why is special being called?\n"); } } // Start of Common methods boolean setSeverity(AlarmSeverity severity, string status) { if(severity<= this.severity) return false; this.severity = severity; this.status = status; this.modifyingAlarm = true; this.alarmSeverity.putIndex(severity); this.alarmStatus.put(status); this.modifyingAlarm = false; } }
RecordCommonSupport implements the following interfaces:
- RecordSupport
- Record support for the fields in RecordCommon.
- Common
- For now this just has the method setSeverity
It has the following private fields:
- instance - The record instance to which it is attached. RecordCommonSupport has a single constructor which is passed the RecordInstance to which it is attached.
- input - Input is a private class that provides access to the fields of disable.
- output - Output is a private class that provides access to processLink.
- severity, ..., modifyingAlarm - private fields for implementing Common.setSeverity
Notes about Input and Output.
- Each of these is a private class to RecordCommonSupport.
- The implementations of each of these private classes is given after the implementaion of RecordCommonSupport.
RecordSupport Methods
destroy
public destroy() {} // destroy not needed for Java
Since Java does garbage collection destroy is not needed. Note that iocCore will call all the link support destroy methods.
initialize
public initialize(int pass) { if(pass==0) return; input = new Input(instance); output = new Output(instance); alarmSeverity = instance.getField("alarmSeverity"); alarmStatus = instance.getField("alarmStatus"); severity = alarmSeverity.get(); alarmStatus.get(status); }
During the first pass of initialization, nothing needs to be done. Before initialize is called on pass 1, iocInit has already called link support so that it connects. Initialize just creates it's private class instances for Input and Output, and initializes the private fields for implementing setSeverity.
process
process is called by dbProcess at the beginning of record processing, when a request is made to process while the record is active, and after the record specific record support completes. During the beginning of record processing process takes care of field disable, via class Input, During the end of record processing process takes care of field processLink, via class Output
public ProcessReturn process(processState state,Callback callback) { if(state==processCancel) { input.process(state,callback); output.process(state,callback); return processDone; } if(state==processStart) { ProcessReturn result = input.process(state,callback); if(result!=processDone) return result; } if(state==processFinish) { ProcessReturn result = output.process(state,callback); if(result!=processDone) return result; } return output.process(state,callback) }
special
special is called when any of the fields in disable, alarmStatus, alarmSeverity, or processLink are changed.
public boolean special(boolean after,Dbf[] field) { int nlevels = field.length; assert(nlevels>0); if(index==alarmStatusIndex || index==alarmSeverityIndex) { if(!alarm.modifyingAlarm) return false; return true; } if(!after) return; switch(index) { case disableIndex: { if(nlevels==1) { input = new Input(instance); } else { input.special(instance,Dbf[1]); } break; } case processLinkIndex : output = new Output(instance); break; default: printf("Why is special being called?\n"); } }
setSeverity
This is the implementation of Common.setSeverity.
boolean setSeverity(AlarmSeverity severity, string status) { if(severity<= this.severity) return false; this.severity = severity; this.status = status; this.modifyingAlarm = true; this.alarmSeverity.putIndex(severity); this.alarmStatus.put(status); this.modifyingAlarm = false; }
Input
This is the package private class the handles disable.
class Input implements Callback{ RecordInstance instance; DisableData disable; LinkInt16 disableSupport; Callback processCallback; Input(RecordInstance instance) { this.instance = instance; DisplayLimitAccess.get( (DbfStruct)instance.getField("disable"),disable); disableSupport = DbAccess.getLinkSupport(disable.disableLink); } public ProcessReturn process(processState state,Callback callback) { switch(state) { case processCancel: processCallback = null; disableSupport.cancel(); return(processDone); case processStart: LinkWaitResult result; result = disableSupport.getWait(disable.disableInput,this); switch(result) { case linkNoop: case linkDone: if(disable.disableInput==disable.disableValue) return processAbort; return processDone; case linkWait: case linkWaitBlock: processCallback = callback; return processActive; default: throw java.lang.IllegalStateException; } } void special(RecordInstance instance,Dbf field) { int16 index = Dbf.getIndex(); switch(index) { case disableValueIndex: disable.disableValue = ((DbfInt16)Dbf).get(); break; case disableInputIndex: disable.disableInput = ((DbfInt16)Dbf).get(); break; case disableAlarmSeverityIndex: disable.alarmSeverity = ((dbfMenu)Dbf).getIndex(); break; case disableLinkIndex: case disableIndex: DisplayLimitAccess.get( (DbfStruct)instance.getField("disable"),disable); disableSupport = disable.disableLink.getSupport(); break; default: throw java.lang.IllegalStateException; } } // Start of Callback methods public void done() { DbAccess.lock(instance); Callback callback = processCallback; processCallback = null; DbAccess.unlock(instance); if(callback!=null) callback.done(); } public void failure() { done(); } }
Output
This is the package private class that handles processLink.
class OutputLink { Link link; LinkProcess support; void init(RecordInstance instance,String linkFieldName) { DbfLink link = (DbfLink)instance.getField(linkFieldName); support = DbAccess.getLinkSupport(link); } }; class Output { RecordInstance instance; int nextLink; int numberLinksActive; OutputLink[] link; Callback processCallback; Output(RecordInstance instance) { this.instance = instance; DbfArray array = instance.getField("processLink"); int n = array.getNelements(); link = new OutputLink[n]; for(i=0; i< n; i++) { String field = "processLink[" + "i" + "]"; link[i].init(instance,field); } } public ProcessReturn process(processState state,Callback processCallback) { switch(state) { case processCancel: processCallback = null; for(int i=0; i<link.length) { link[i].support.cancel(); } return(processDone); case processDone: nextLink = 0; numberLinksActive = 0; // fall through to processOutputActive case processActive: LinkWaitResult result = linkWait; while(nextLink< link.length) { result = link[nextLink].support.process(this); if(result==linkWait || result==linkWaitBlock) { link[nextLink].active = true; numberLinksActive++; } if(result==linkWaitBlock) break; output.nextLink++; } if(output.numberLinksActive==0) return processDone; return processActive; default: throw java.lang.IllegalStateException; } // Start of Callback methods public void done() { DbAccess.lock(instance); numberLinksActive--; Callback callback = processCallback; processCallback = null; DbAccess.unlock(instance); if(numberLinksActive==0 && callback!=null) callback.done(); } public void failure() { done(); } }
RecordCommonSupportFactory
This is the factory for creating an RecordCommonSupport. It is called by dbLoadRecords.
public class RecordCommonSupportFactory implements RecordSupportFactory{ RecordSupport create(RecordInstance instance) { return new RecordCommonSupport(instance); } void destroy(RecordSupport support) { RecordCommonSupport RecordCommonSupport = support; RecordCommonSupport.destroy(); } }
public final class RecordCommonSupportFactoryRegister { static public createAndRegister() { RecordCommonSupportFactory factory = new RecordCommonSupportFactory; RegisterSupport.record(factory,"RecordCommon"); } }
Question Who calls RecordCommonSupportFactoryRegister.createAndRegister?