Difference between revisions of "V4 Design: IocRecord"
MartyKraimer (talk | contribs) |
MartyKraimer (talk | contribs) |
||
(2 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
= EPICS V4: IocRecord = | = EPICS V4: IocRecord = | ||
September 15 2005 | |||
---- | ---- | ||
This document describes the V4 implementation of what was provided by | This document describes the V4 implementation of what was provided by | ||
Line 22: | Line 22: | ||
# V4 Design: Record Processing | # V4 Design: Record Processing | ||
# V4 Design: dbdInterfaces | # V4 Design: dbdInterfaces | ||
# V4 Design: Runtime interfaces | |||
Unless the reader is familiar with | Unless the reader is familiar with these most of this document will | ||
be very difficult to understand. | be very difficult to understand. | ||
Line 30: | Line 31: | ||
# Java provides facilities that make it easy to handle strings, arrays, and structures. | # Java provides facilities that make it easy to handle strings, arrays, and structures. | ||
An implementaion of | An implementaion of IocRecordSupport is presented for two reasons: | ||
# It demonstrates how to implement code that uses or implements the interface described in "V4 Design: dbdInterfaces". | # It demonstrates how to implement code that uses or implements the interface described in "V4 Design: dbdInterfaces" and "V4 Design: Runtime interfaces". | ||
# It helps refine the interfaces described in | # It helps refine the interfaces described in them | ||
---- | ---- | ||
Line 41: | Line 42: | ||
<tt>dbCommon.dbd</tt> defines the following: | <tt>dbCommon.dbd</tt> defines the following: | ||
# menu definitions for | # menu definitions for IocRecord fields | ||
menu(menuPriority) { | menu(menuPriority) { | ||
choice(menuPriorityLow, "Low") | choice(menuPriorityLow, "Low") | ||
Line 74: | Line 75: | ||
} | } | ||
struct( | struct(MonitorLink) { | ||
field(pvname,string) { link} | |||
field(process,bool) // process this record when monitor occurs | |||
field(inheritSeverity,bool) | |||
} | |||
struct(InputLink) { | |||
field(pvname,string) { link} | |||
field(parallel,bool) | |||
field(process,bool) | |||
field(wait,bool) | |||
field(inheritSeverity,bool) | |||
} | |||
struct(OutputLink) { | |||
field(pvname,string) { link} | field(pvname,string) { link} | ||
field(parallel,bool) | field(parallel,bool) | ||
field(process,bool) | field(process,bool) | ||
field(wait,bool) | field(wait,bool) | ||
field(inheritSeverity,bool) | field(inheritSeverity,bool) | ||
} | |||
struct(ProcessLink) { | |||
field(pvname,string) { link} | |||
field(parallel,bool) | |||
field(wait,bool) | |||
} | } | ||
link( | link(in,"MonitorLink",MonitorLink); | ||
link(in,"InputLink",InputLink); | |||
link(out,"OutputLink",OutputLink); | |||
link(process,"ProcessLink",ProcessLink); | |||
#definitions for common properties | #definitions for common properties | ||
struct(TimeStamp) { | struct(TimeStamp) { | ||
field( | field(secondsPastEpoch,int64) | ||
field(nanoSeconds, | field(nanoSeconds,int32) | ||
} | } | ||
Line 101: | Line 121: | ||
} | } | ||
<b> | <b>Event NEEDS NEW DEFINITIONS</b> | ||
struct Event { | struct Event { | ||
field(eventNumber,int16) { | field(eventNumber,int16) { | ||
Line 115: | Line 134: | ||
== dbCommon.java == | == dbCommon.java == | ||
</center> | </center> | ||
Link support must register for each of the <tt>link</tt> definitions. | |||
From <tt>dbCommon.dbd</tt> the following class implementations are generated: | |||
* For the link structures: | |||
** <tt>MonitorLink</tt> and <tt>MonitorLinkData</tt>, and <tt>MonitorLinkSupport</tt> | |||
** <tt>InputLink</tt>, <tt>InputLinkData</tt>, and <tt>InputLinkSupport</tt> | |||
** <tt>OutputLink</tt>, <tt>OutputLinkData</tt>, and <tt>OutputLinkSupport</tt> | |||
** <tt>ProcessLink</tt>, <tt>ProcessLinkData</tt>, and <tt>ProcessLinkSupport</tt> | |||
* For TimeStamp | |||
** <tt>TimeStamp</tt>, <tt>TimeStampData</tt>, and <tt>TimeStampSupport</tt> | |||
* For Scan | |||
** <tt>Scan</tt>, <tt>ScanData</tt>, and <tt>ScanSupport</tt> | |||
See "V4 Design: Runtime interfaces" for an example of how these classes are defined. | |||
---- | |||
<center> | |||
== iocRecord.dbd == | |||
</center> | |||
<tt>IocRecord.dbd</tt> must be part of every record, and defines the following: | <tt>IocRecord.dbd</tt> must be part of every record, and defines the following: | ||
struct Disable { | struct Disable { | ||
Line 210: | Line 210: | ||
* previous value fields - All puts to database fields will be posted. The layer above will decide if clients should be notified of changes. | * previous value fields - All puts to database fields will be posted. The layer above will decide if clients should be notified of changes. | ||
Implementations of <tt>Disable</tt>, <tt>DisableData</tt>, | |||
and <tt>DisableDataSupport</tt> | |||
are automatically generated. | |||
An implementations of IocRecord is also generated. | |||
See "V4 Design: Runtime interfaces" for an example of the generated | |||
classes. | |||
---- | ---- | ||
<center> | <center> | ||
== | == iocRecordSupport.java == | ||
</center> | </center> | ||
This | === Overview === | ||
This section describes the java implementation of iocRecord | |||
functionality. This code handles processing of the following fields | |||
of IocRecord: | |||
; <tt>disable</tt> | |||
: Decides if the record is disabled. | |||
; <tt>alarmStatus</tt> and <tt>alarmSeverity</tt> | |||
: The only way to change alarmStatus and alarmSeverity is via interface Common, which is implemented by IocRecordSupport. | |||
; <tt>processLink</tt> | |||
: This is an array of process links, which replace the V3 <tt>FLNK</tt> | |||
The following subsection contains the complete code for IocRecordSupport.java. | |||
The remaining subsections discuss each part of the code. | |||
=== IocCommon.java === | |||
This defines | |||
interface Common { | |||
bool setSeverity(AlarmSeverity severity, string status); | |||
} | } | ||
class | === IocRecordSupport.java === | ||
public | enum Mode {modeNone,modeInput,modeOutput}; | ||
public | |||
public class IocRecordSupport extends RecordSupport | |||
implements Callback, Common { | |||
private RecordInstance instance; | |||
private Mode mode; | |||
private Input input; | |||
private Output output; | |||
private Alarm alarm; | |||
private bool requestProcess; | |||
// Constructor | |||
public IocRecordSupport(RecordInstance instance) { | |||
this.instance = instance; | |||
} | |||
// Beginning of RecordSupport | |||
public initialize(int pass) { | |||
if(pass==0) return; | |||
input.init(instance); | |||
output.init(instance); | |||
alarm.init(instance); | |||
} | |||
public destroy() {} // destroy not needed for Java | |||
public processState process(processState state) { | |||
switch(state) { | |||
case processCancel: mode = modeNone; return processDone; | |||
case processStart: { | |||
mode = modeInput; | |||
requestProcess = false; | |||
LinkWaitResult result = input.disableSupport.getWait( | |||
input.disableInput,0.0,this); | |||
if(result==linkNoop || result==linkDone) return processDone; | |||
requestProcess = true; | |||
} | |||
// fall through to processInputActive | |||
case processInputActive: { | |||
if(requestProcess) return processInputActive; | |||
if(input.disable.disableValue == disable.disableInput) | |||
return processDone; | |||
return processActive; | |||
} | |||
case processDone: { | |||
mode = modeOutput; | |||
output.nextLink = 0; | |||
output.numberLinksActive = 0; | |||
} | |||
// fall through to processOutputActive | |||
case processOutputActive: | |||
LinkWaitResult result = linkWaitParallel; | |||
requestProcess = false; | |||
while(output.nextLink< output.link.length) { | |||
if(result==linkWaitSequential) break; | |||
result = output.link[nextLink].support.processWait(0.0,this); | |||
if(result==linkWaitSequential || result==linkWaitParallel) | |||
output.numberLinksActive++ | |||
output.nextLink++; | |||
} | |||
if(output.numberLinksActive==0) { | |||
mode = modeNone; | |||
return processDone; | |||
} | |||
requestProcess = true; | |||
return processOutputActive; | |||
default: throw java.lang.IllegalStateException; | |||
} | |||
} | |||
public bool special(bool 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.init(instance); | |||
} else { | |||
input.special(instance,Dbf[1]); | |||
} | |||
break; | |||
} | |||
case processLinkIndex : output.init(instance); break; | |||
default: printf("Why is special being called?\n"); | |||
} | |||
} | |||
// Start of Callback methods | |||
-- | public void done() { | ||
lock(instance); | |||
= | switch(mode) { | ||
case modeNone: | |||
unlock(instance) | |||
throw java.lang.IllegalStateException; | |||
case modeInput: | |||
if(requestProcess) { | |||
requestProcess = false; | |||
DbAccess.process(instance); | |||
} | |||
break; | |||
case modeOutput: | |||
output.numberLinksActive--; | |||
if(output.numberLinksActive==0 && requestProcess) { | |||
requestProcess = false; | |||
DbAccess.process(instance); | |||
} | |||
if(output.numberLinksActive==0 && requestProcess) | |||
break; | |||
} | |||
unlock(instance) | |||
} | |||
public void failure() { done(); } | |||
// Start of Common methods | |||
bool setSeverity(AlarmSeverity severity, string status) { | |||
Alarm alarm = this.alarm; | |||
bool setSeverity(AlarmSeverity severity, string status); | if(severity<= alarm.severity) return false; | ||
alarm.severity = severity; | |||
alarm.status = status; | |||
alarm.modifyingAlarm = true; | |||
alarm.alarmSeverity.putIndex(severity); | |||
alarm.alarmStatus.put(status); | |||
alarm.modifyingAlarm = false; | |||
} | |||
} | |||
// Definitions for modeInput | |||
class Input { | |||
DisableData disable; | |||
LinkSupport disableSupport; | |||
DbfInt16 disableInput; | |||
DbfInt16 disableValue; | |||
DbfInt16 alarmSeverity; | |||
void init(RecordInstance instance) { | |||
RecordAccess recordAccess = instance.getIocRecordAccess(); | |||
DbfLink link = recordAccess.getField("disable.disableLink"); | |||
disableSupport = link.getSupport(); | |||
DisplayLimitAccess.get( | |||
recordAccess.getField("disable"),disable); | |||
recordAccess.getField("disable.disableInput",disableInput); | |||
} | |||
void special(RecordInstance instance,Dbf field) { | |||
int16 index = Dbf.getIndex(); | |||
switch(index) { | |||
case disableValueIndex: | |||
disableValue = ((DbfInt16)Dbf).get(); break; | |||
case disableInputIndex: | |||
disableInput = ((DbfInt16)Dbf).get(); break; | |||
case disableAlarmSeverityIndex: | |||
alarmSeverity = ((dbfMenu)Dbf).getIndex(); break; | |||
case disableLinkIndex: | |||
init(instance); break; | |||
default: | |||
throw java.lang.IllegalStateException; | |||
} | |||
} | |||
} | } | ||
// Definitions for modeOutput | |||
class OutputLink { | |||
== | Link link; | ||
LinkSupport support; | |||
void init(RecordInstance instance,String linkFieldName) { | |||
RecordAccess recordAccess = instance.getIocRecordAccess(); | |||
DbfLink link = recordAccess.getField(linkFieldName); | |||
support = link.getSupport(); | |||
} | |||
}; | |||
class Output { | |||
int nextLink; | |||
int numberLinksActive; | |||
OutputLink[] link; | |||
void init(RecordInstance instance) { | |||
RecordAccess recordAccess = instance.getIocRecordAccess(); | |||
DbfArray array = recordAccess.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); | |||
} | |||
} | |||
} | |||
// Definitions for alarm handling | |||
class Alarm { | |||
short severity; | |||
String status; | |||
; | DbfMenu alarmSeverity; | ||
DbfString alarmStatus; | |||
; | bool modifyingAlarm; | ||
void init(RecordInstance instance) { | |||
RecordAccess recordAccess = instance.getIocRecordAccess(); | |||
alarmSeverity = recordAccess.getField("alarmSeverity"); | |||
alarmStatus = recordAccess.getField("alarmStatus"); | |||
} | |||
} | |||
=== Beginning of class definition === | === Beginning of class definition === | ||
enum Mode {modeNone,modeInput,modeOutput}; | enum Mode {modeNone,modeInput,modeOutput}; | ||
public class | public class IocRecordSupport extends RecordSupport | ||
implements Callback, Common { | |||
private RecordInstance instance; | private RecordInstance instance; | ||
private Mode mode; | private Mode mode; | ||
Line 302: | Line 463: | ||
// Constructor | // Constructor | ||
public | public IocRecordSupport(RecordInstance instance) { | ||
this.instance = instance; | this.instance = instance; | ||
} | } | ||
IocRecordSupport implements the following interfaces: | |||
; < | ; <tt>RecordSupport</tt> | ||
: Record support for the fields in IocRecord. | : Record support for the fields in IocRecord. | ||
; < | ; <tt>Callback</tt> | ||
: The callbacks called by link support | : The callbacks called by link support | ||
; < | ; <tt>Common</tt> | ||
: For now this just has the method < | : For now this just has the method <tt>setSeverity</tt> | ||
It has the following private fields: | It has the following private fields: | ||
* < | * <tt>instance</tt> - The record instance to which it is attached. <tt>IocRecordSupport</tt> has a single constructor which is passed the <tt>RecordInstance</tt> to which it is attached. | ||
* < | * <tt>mode</tt> - This keeps the state for record processing: | ||
** < | ** <tt>modeNone</tt> - The record is not being processed. | ||
** < | ** <tt>modeInput</tt> - The disable link is active but not complete. | ||
** < | ** <tt>modeOutput</tt> - The processLinks are active but not complete. | ||
* < | * <tt>input</tt> - Input is a private class that provides access to the fields of disable. | ||
* < | * <tt>output</tt> - Output is a private class that provides access to processLink. | ||
* < | * <tt>alarm</tt> - Alarm is a private class that provides access to fields alarmSeverity and alarmStatus. | ||
* < | * <tt>requestProcess</tt> - This is used by callback to decide if a request should be made to process the record. | ||
Notes about < | Notes about <tt>Input</tt>, <tt>Output</tt>, and <tt>Alarm</tt>. | ||
Each of these is a private class to | * Each of these is a private class to IocRecordSupport. | ||
Each makes fields available to | * Each makes fields available to IocRecordSupport. | ||
Each has "introspection" code that gets the values of the private | * Each has "introspection" code that gets the values of the private fields from IocRecord fields during record initialization of if the an IocRecord fields is changed via a call to <tt>Dbf.put</tt>. | ||
fields from IocRecord fields during record initialization of if the | * The implementations of each of these private classes is given after the implementaion of IocRecordSupport. | ||
an IocRecord fields is changed via a call to < | |||
The implementations of each of these private classes is given after the implementaion of | |||
Line 360: | Line 519: | ||
==== process ==== | ==== process ==== | ||
< | <tt>process</tt> is called by dbProcess at the beginning of record processing | ||
and after the record specific record support completes. | and after the record specific record support completes. | ||
During the beginning of record processing | During the beginning of record processing | ||
process takes care of field < | process takes care of field <tt>disable</tt> | ||
During the end of record processing process | During the end of record processing process | ||
takes care of field < | takes care of field <tt>processLink</tt>. | ||
A few features of < | A few features of <tt>process</tt> are: | ||
* implements a state machine that handles the links. | * implements a state machine that handles the links. | ||
* interacts with Callback, which is called by link support when links complete. | * interacts with Callback, which is called by link support when links complete. | ||
Line 374: | Line 533: | ||
public processState process(processState state) { | public processState process(processState state) { | ||
switch(state) { | switch(state) { | ||
case processCancel: mode = modeNone; return; | case processCancel: mode = modeNone; return processDone; | ||
case | case processStart: { | ||
mode = modeInput; | mode = modeInput; | ||
requestProcess = false; | requestProcess = false; | ||
Line 418: | Line 577: | ||
==== special ==== | ==== special ==== | ||
< | <tt>special</tt> is called when any of the fields in <tt>disable</tt>, | ||
< | <tt>alarmStatus</tt>, <tt>alarmSeverity</tt>, or <tt>processLink</tt> are changed. | ||
public bool special(bool after,Dbf[] field) { | public bool special(bool after,Dbf[] field) { | ||
int nlevels = field.length; | int nlevels = field.length; | ||
Line 429: | Line 588: | ||
if(!after) return; | if(!after) return; | ||
switch(index) { | switch(index) { | ||
case disableIndex: { | case disableIndex: { | ||
if(nlevels==1) { | if(nlevels==1) { | ||
Line 447: | Line 605: | ||
// Start of Callback methods | // Start of Callback methods | ||
public void done() { | public void done() { | ||
lock(instance); | |||
switch(mode) { | switch(mode) { | ||
case modeNone: throw java.lang.IllegalStateException; | case modeNone: | ||
unlock(instance); | |||
throw java.lang.IllegalStateException; | |||
case modeInput: | case modeInput: | ||
if(requestProcess) DbAccess.process(instance); | if(requestProcess) { | ||
requestProcess = false; | requestProcess = false; | ||
DbAccess.process(instance); | |||
} | |||
break; | |||
case modeOutput: | |||
output.numberLinksActive--; | |||
if(output.numberLinksActive==0 && requestProcess) { | |||
requestProcess = false; | |||
DbAccess.process(instance); | |||
} | |||
return; | return; | ||
} | } | ||
unlock(instance); | |||
} | } | ||
public void | public void failure() { done(); } | ||
=== Common methods === | === Common methods === | ||
For now the only method is < | For now the only method is <tt>setSeverity,</tt> | ||
The only way code can change severity and status is to call this method. | The only way code can change severity and status is to call this method. | ||
Line 480: | Line 646: | ||
=== Input === | === Input === | ||
This is a private class for | This is a private class for IocRecordSupport. | ||
It directly accesses the fields in this class. | It directly accesses the fields in this class. | ||
The init and special methods are called to get values for the private fields. | The init and special methods are called to get values for the private fields. | ||
Line 519: | Line 685: | ||
=== OutputLink and Output === | === OutputLink and Output === | ||
Output is a private class for | Output is a private class for IocRecordSupport. | ||
It directly accesses the fields in this class. | It directly accesses the fields in this class. | ||
The init method is called to get values for the private fields. | The init method is called to get values for the private fields. | ||
Line 552: | Line 718: | ||
=== Alarm === | === Alarm === | ||
This is a private class for | This is a private class for IocRecordSupport. | ||
It directly accesses the fields in this class. | It directly accesses the fields in this class. | ||
The init method is called to get values for the private fields. | The init method is called to get values for the private fields. | ||
// Definitions for alarm handling | // Definitions for alarm handling | ||
class Alarm { | class Alarm { | ||
Line 569: | Line 736: | ||
} | } | ||
=== | === IocRecordSupportFactory === | ||
This is the factory for creating an | This is the factory for creating an IocRecordSupport. | ||
It is called by dbLoadRecords. | It is called by dbLoadRecords. | ||
public | public class IocRecordSupportFactory implements RecordSupportFactory{ | ||
RecordSupport create(RecordInstance instance) { | RecordSupport create(RecordInstance instance) { | ||
return new | return new IocRecordSupport(instance); | ||
} | } | ||
void destroy(RecordSupport support) { | void destroy(RecordSupport support) { | ||
IocRecordSupport iocRecordSupport = support; | |||
iocRecordSupport.destroy(); | |||
} | |||
} | |||
public final class IocRecordSupportFactoryRegister { | |||
static public createAndRegister() { | |||
IocRecordSupportFactory factory = new IocRecordSupportFactory; | |||
RegisterSupport.record(factory,"IocRecord"); | |||
} | } | ||
} | } | ||
Question | <b>Question</b> | ||
Who calls IocRecordSupportFactoryRegister.createAndRegister? |
Latest revision as of 19:30, 15 September 2005
EPICS V4: IocRecord
September 15 2005
This document describes the V4 implementation of what was provided by the V3 dbCommon. It provides the Java version of code that implements the functionality.
For V4 dbCommon.dbd and IocRecord.dbd replace the V3 dbCommon.dbd. dbCommon.dbd define widely used definitions and IocRecord.dbd defines the fields that are common to all record types.
This document describes the following:
- Database Definition Files
- The database definition files for dbCommon.dbd and iocRecord.dbd. Together these are the replacement for the V3 dbCommon.
- Java code generated from the database definitions.
- The automatically generated code from dbCommon.dbd and iocRecord.dbd
- Java code that implements iocRecord.
- A proposed implementation of iocRecord.
This document requires that the reader be familiar with:
- V3 iocCore
- V4 Design: Record Processing
- V4 Design: dbdInterfaces
- V4 Design: Runtime interfaces
Unless the reader is familiar with these most of this document will be very difficult to understand.
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 IocRecordSupport is presented for two reasons:
- It demonstrates how to implement code that uses or implements the interface described in "V4 Design: dbdInterfaces" and "V4 Design: Runtime interfaces".
- It helps refine the interfaces described in them
Database Definitions
dbCommon.dbd defines the following:
# menu definitions for IocRecord fields menu(menuPriority) { choice(menuPriorityLow, "Low") choice(menuPriorityMedium, "Medium") choice(menuPriorityHigh, "High") }
menu(menuScan) { choice(menuScanPassive, "Passive") choice(menuScanEvent, "Event") choice(menuScanInterrupt, "Interrupt") choice(menuScan10second, "10 second") choice(menuScan5second, "5 second") choice(menuScan2second, "2 second") choice(menuScan1second, "1 second") choice(menuScan_5second, ".5 second") choice(menuScan_2second, ".2 second") choice(menuScan_1second, ".1 second") }
menu(menuAlarmSevr) { choice(menuAlarmSevrNone, "None") choice(menuAlarmSevrMinor, "Minor") choice(menuAlarmSevrMajor, "Major") choice(menuAlarmSevrInvalid, "Invalid") }
menu(menuConvert) { choice(menuConvertRaw, "Raw") choice(menuConvertLinear, "Linear") choice(menuConvertTable, "Table") }
struct(MonitorLink) { field(pvname,string) { link} field(process,bool) // process this record when monitor occurs field(inheritSeverity,bool) } struct(InputLink) { field(pvname,string) { link} field(parallel,bool) field(process,bool) field(wait,bool) field(inheritSeverity,bool) } struct(OutputLink) { field(pvname,string) { link} field(parallel,bool) field(process,bool) field(wait,bool) field(inheritSeverity,bool) } struct(ProcessLink) { field(pvname,string) { link} field(parallel,bool) field(wait,bool) }
link(in,"MonitorLink",MonitorLink); link(in,"InputLink",InputLink); link(out,"OutputLink",OutputLink); link(process,"ProcessLink",ProcessLink);
#definitions for common properties struct(TimeStamp) { field(secondsPastEpoch,int64) field(nanoSeconds,int32) }
struct Scan { field(scan,menu(menuScan)) { special(yes) } field(phase,int16) field(priority,menu(menuPriority)) { special(yes) } }
Event NEEDS NEW DEFINITIONS
struct Event { field(eventNumber,int16) { special(yes) } field(timeStampEvent,int16) field(timeStampLink,link(in)) }
dbCommon.java
Link support must register for each of the link definitions.
From dbCommon.dbd the following class implementations are generated:
- For the link structures:
- MonitorLink and 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.
iocRecord.dbd
IocRecord.dbd must be part of every record, and defines the following:
struct Disable { field(disableValue,int16) { default("1") } field(disableInput,int16) field(disableLink,link(in)) field(disableAlarmSeverity,menu(menuAlarmSevr)) }
record(IocRecord) { field(description,string) field(scan,struct(Scan)) field(accessSecurityGroup,string) field(pini,bool) field(disablePutField,bool) field(alarmAckSeverity,menu(menuAlarmSevr)) { design(no) readonly(yes) } field(alarmAckTransient,bool) { readonly(yes) default("YES") } field(udf,bool) { dynamic(yes) default("1") } field(time,struct(timeStamp)) { design(no) dynamic(yes) readonly(yes) } field(disable,struct(Disable)) { special(yes) } field(alarmStatus,string) { default("UDF") } field(alarmSeverity,menu(menuAlarmSevr)) { readonly(yes) default("Invalid") } field(processLink,array([] struct(Link))) { special(yes) } }
Although it has many fewer fields, iocRecord.dbd is a complete replacement for the V3 dbCommon. The following V3 fields are no longer needed:
- private fields - Private fields will truly be privaye to the implementation
- previous value fields - All puts to database fields will be posted. The layer above will decide if clients should be notified of changes.
Implementations of Disable, DisableData, and DisableDataSupport are automatically generated.
An implementations of IocRecord is also generated. See "V4 Design: Runtime interfaces" for an example of the generated classes.
iocRecordSupport.java
Overview
This section describes the java implementation of iocRecord functionality. This code handles processing of the following fields of IocRecord:
- 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 IocRecordSupport.
- processLink
- This is an array of process links, which replace the V3 FLNK
The following subsection contains the complete code for IocRecordSupport.java. The remaining subsections discuss each part of the code.
IocCommon.java
This defines
interface Common { bool setSeverity(AlarmSeverity severity, string status); }
IocRecordSupport.java
enum Mode {modeNone,modeInput,modeOutput}; public class IocRecordSupport extends RecordSupport implements Callback, Common { private RecordInstance instance; private Mode mode; private Input input; private Output output; private Alarm alarm; private bool requestProcess; // Constructor public IocRecordSupport(RecordInstance instance) { this.instance = instance; } // Beginning of RecordSupport public initialize(int pass) { if(pass==0) return; input.init(instance); output.init(instance); alarm.init(instance); } public destroy() {} // destroy not needed for Java
public processState process(processState state) { switch(state) { case processCancel: mode = modeNone; return processDone; case processStart: { mode = modeInput; requestProcess = false; LinkWaitResult result = input.disableSupport.getWait( input.disableInput,0.0,this); if(result==linkNoop || result==linkDone) return processDone; requestProcess = true; } // fall through to processInputActive case processInputActive: { if(requestProcess) return processInputActive; if(input.disable.disableValue == disable.disableInput) return processDone; return processActive; } case processDone: { mode = modeOutput; output.nextLink = 0; output.numberLinksActive = 0; } // fall through to processOutputActive case processOutputActive: LinkWaitResult result = linkWaitParallel; requestProcess = false; while(output.nextLink< output.link.length) { if(result==linkWaitSequential) break; result = output.link[nextLink].support.processWait(0.0,this); if(result==linkWaitSequential || result==linkWaitParallel) output.numberLinksActive++ output.nextLink++; } if(output.numberLinksActive==0) { mode = modeNone; return processDone; } requestProcess = true; return processOutputActive; default: throw java.lang.IllegalStateException; } }
public bool special(bool 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.init(instance); } else { input.special(instance,Dbf[1]); } break; } case processLinkIndex : output.init(instance); break; default: printf("Why is special being called?\n"); } }
// Start of Callback methods public void done() { lock(instance); switch(mode) { case modeNone: unlock(instance) throw java.lang.IllegalStateException; case modeInput: if(requestProcess) { requestProcess = false; DbAccess.process(instance); } break; case modeOutput: output.numberLinksActive--; if(output.numberLinksActive==0 && requestProcess) { requestProcess = false; DbAccess.process(instance); } if(output.numberLinksActive==0 && requestProcess) break; } unlock(instance) } public void failure() { done(); }
// Start of Common methods bool setSeverity(AlarmSeverity severity, string status) { Alarm alarm = this.alarm; if(severity<= alarm.severity) return false; alarm.severity = severity; alarm.status = status; alarm.modifyingAlarm = true; alarm.alarmSeverity.putIndex(severity); alarm.alarmStatus.put(status); alarm.modifyingAlarm = false; } } // Definitions for modeInput class Input { DisableData disable; LinkSupport disableSupport; DbfInt16 disableInput; DbfInt16 disableValue; DbfInt16 alarmSeverity; void init(RecordInstance instance) { RecordAccess recordAccess = instance.getIocRecordAccess(); DbfLink link = recordAccess.getField("disable.disableLink"); disableSupport = link.getSupport(); DisplayLimitAccess.get( recordAccess.getField("disable"),disable); recordAccess.getField("disable.disableInput",disableInput); } void special(RecordInstance instance,Dbf field) { int16 index = Dbf.getIndex(); switch(index) { case disableValueIndex: disableValue = ((DbfInt16)Dbf).get(); break; case disableInputIndex: disableInput = ((DbfInt16)Dbf).get(); break; case disableAlarmSeverityIndex: alarmSeverity = ((dbfMenu)Dbf).getIndex(); break; case disableLinkIndex: init(instance); break; default: throw java.lang.IllegalStateException; } } }
// Definitions for modeOutput class OutputLink { Link link; LinkSupport support; void init(RecordInstance instance,String linkFieldName) { RecordAccess recordAccess = instance.getIocRecordAccess(); DbfLink link = recordAccess.getField(linkFieldName); support = link.getSupport(); } }; class Output { int nextLink; int numberLinksActive; OutputLink[] link; void init(RecordInstance instance) { RecordAccess recordAccess = instance.getIocRecordAccess(); DbfArray array = recordAccess.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); } } }
// Definitions for alarm handling class Alarm { short severity; String status; DbfMenu alarmSeverity; DbfString alarmStatus; bool modifyingAlarm; void init(RecordInstance instance) { RecordAccess recordAccess = instance.getIocRecordAccess(); alarmSeverity = recordAccess.getField("alarmSeverity"); alarmStatus = recordAccess.getField("alarmStatus"); } }
Beginning of class definition
enum Mode {modeNone,modeInput,modeOutput}; public class IocRecordSupport extends RecordSupport implements Callback, Common { private RecordInstance instance; private Mode mode; private Input input; private Output output; private Alarm alarm; private bool requestProcess; // Constructor public IocRecordSupport(RecordInstance instance) { this.instance = instance; }
IocRecordSupport implements the following interfaces:
- RecordSupport
- Record support for the fields in IocRecord.
- Callback
- The callbacks called by link support
- Common
- For now this just has the method setSeverity
It has the following private fields:
- instance - The record instance to which it is attached. IocRecordSupport has a single constructor which is passed the RecordInstance to which it is attached.
- mode - This keeps the state for record processing:
- modeNone - The record is not being processed.
- modeInput - The disable link is active but not complete.
- modeOutput - The processLinks are active but not complete.
- 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.
- alarm - Alarm is a private class that provides access to fields alarmSeverity and alarmStatus.
- requestProcess - This is used by callback to decide if a request should be made to process the record.
Notes about Input, Output, and Alarm.
- Each of these is a private class to IocRecordSupport.
- Each makes fields available to IocRecordSupport.
- Each has "introspection" code that gets the values of the private fields from IocRecord fields during record initialization of if the an IocRecord fields is changed via a call to Dbf.put.
- The implementations of each of these private classes is given after the implementaion of IocRecordSupport.
RecordSupport
initialize
// Beginning of RecordSupport public initialize(int pass) { if(pass==0) return; input.init(instance); output.init(instance); alarm.init(instance); }
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 calls its private class init methods. They get the current values of their private fields.
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.
process
process is called by dbProcess at the beginning of record processing and after the record specific record support completes. During the beginning of record processing process takes care of field disable During the end of record processing process takes care of field processLink.
A few features of process are:
- implements a state machine that handles the links.
- interacts with Callback, which is called by link support when links complete.
- interacts with special, which is called when fields in IocRecord are modified.
public processState process(processState state) { switch(state) { case processCancel: mode = modeNone; return processDone; case processStart: { mode = modeInput; requestProcess = false; LinkWaitResult result = input.disableSupport.getWait( input.disableInput,0.0,this); if(result==linkNoop || result==linkDone) return processDone; requestProcess = true; } // fall through to processInputActive case processInputActive: { if(requestProcess) return processInputActive; if(input.disable.disableValue == disable.disableInput) return processDone; return processActive; } case processDone: { mode = modeOutput; output.nextLink = 0; output.numberLinksActive = 0; } // fall through to processOutputActive case processOutputActive: LinkWaitResult result = linkWaitParallel; requestProcess = false; while(output.nextLink< output.link.length) { if(result==linkWaitSequential) break; result = output.link[nextLink].support.processWait(0.0,this); if(result==linkWaitSequential || result==linkWaitParallel) output.numberLinksActive++ output.nextLink++; } if(output.numberLinksActive==0) { mode = modeNone; return processDone; } requestProcess = true; return processOutputActive; default: throw java.lang.IllegalStateException; } }
special
special is called when any of the fields in disable, alarmStatus, alarmSeverity, or processLink are changed.
public bool special(bool 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.init(instance); } else { input.special(instance,Dbf[1]); } break; } case processLinkIndex : output.init(instance); break; default: printf("Why is special being called?\n"); } }
Callback methods
These are the callback methods that are called by link support.
// Start of Callback methods public void done() { lock(instance); switch(mode) { case modeNone: unlock(instance); throw java.lang.IllegalStateException; case modeInput: if(requestProcess) { requestProcess = false; DbAccess.process(instance); } break; case modeOutput: output.numberLinksActive--; if(output.numberLinksActive==0 && requestProcess) { requestProcess = false; DbAccess.process(instance); } return; } unlock(instance); } public void failure() { done(); }
Common methods
For now the only method is setSeverity, The only way code can change severity and status is to call this method.
// Start of Common methods bool setSeverity(AlarmSeverity severity, string status) { Alarm alarm = this.alarm; if(severity<= alarm.severity) return false; alarm.severity = severity; alarm.status = status; alarm.modifyingAlarm = true; alarm.alarmSeverity.putIndex(severity); alarm.alarmStatus.put(status); alarm.modifyingAlarm = false; } }
Input
This is a private class for IocRecordSupport. It directly accesses the fields in this class. The init and special methods are called to get values for the private fields.
// Definitions for modeInput class Input { DisableData disable; LinkSupport disableSupport; DbfInt16 disableInput; DbfInt16 disableValue; DbfInt16 alarmSeverity; void init(RecordInstance instance) { RecordAccess recordAccess = instance.getIocRecordAccess(); DbfLink link = recordAccess.getField("disable.disableLink"); disableSupport = link.getSupport(); DisplayLimitAccess.get( recordAccess.getField("disable"),disable); recordAccess.getField("disable.disableInput",disableInput); } void special(RecordInstance instance,Dbf field) { int16 index = Dbf.getIndex(); switch(index) { case disableValueIndex: disableValue = ((DbfInt16)Dbf).get(); break; case disableInputIndex: disableInput = ((DbfInt16)Dbf).get(); break; case disableAlarmSeverityIndex: alarmSeverity = ((dbfMenu)Dbf).getIndex(); break; case disableLinkIndex: init(instance); break; default: throw java.lang.IllegalStateException; } } }
OutputLink and Output
Output is a private class for IocRecordSupport. It directly accesses the fields in this class. The init method is called to get values for the private fields. OutputLink is used by Output.
// Definitions for modeOutput class OutputLink { Link link; LinkSupport support; void init(RecordInstance instance,String linkFieldName) { RecordAccess recordAccess = instance.getIocRecordAccess(); DbfLink link = recordAccess.getField(linkFieldName); support = link.getSupport(); } }; class Output { int nextLink; int numberLinksActive; OutputLink[] link; void init(RecordInstance instance) { RecordAccess recordAccess = instance.getIocRecordAccess(); DbfArray array = recordAccess.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); } } }
Alarm
This is a private class for IocRecordSupport. It directly accesses the fields in this class. The init method is called to get values for the private fields.
// Definitions for alarm handling class Alarm { short severity; String status; DbfMenu alarmSeverity; DbfString alarmStatus; bool modifyingAlarm; void init(RecordInstance instance) { RecordAccess recordAccess = instance.getIocRecordAccess(); alarmSeverity = recordAccess.getField("alarmSeverity"); alarmStatus = recordAccess.getField("alarmStatus"); } }
IocRecordSupportFactory
This is the factory for creating an IocRecordSupport. It is called by dbLoadRecords.
public class IocRecordSupportFactory implements RecordSupportFactory{ RecordSupport create(RecordInstance instance) { return new IocRecordSupport(instance); } void destroy(RecordSupport support) { IocRecordSupport iocRecordSupport = support; iocRecordSupport.destroy(); } }
public final class IocRecordSupportFactoryRegister { static public createAndRegister() { IocRecordSupportFactory factory = new IocRecordSupportFactory; RegisterSupport.record(factory,"IocRecord"); } }
Question Who calls IocRecordSupportFactoryRegister.createAndRegister?