Difference between revisions of "V4 Design: IocRecord"

From EPICSWIKI
 
Line 1: Line 1:
= EPICS V4: IocRecord =
= EPICS V4: IocRecord =
August 30 2005
August 31 2005
----
----
This document describes the V4 implementation of what was provided by
This document describes the V4 implementation of what was provided by
Line 30: Line 30:
# 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 IocRecordInterface is presented for two reasons:
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".
# It helps refine the interfaces described in "V4 Design: dbdInterfaces".
# It helps refine the interfaces described in "V4 Design: dbdInterfaces".
Line 74: Line 74:
     }
     }


     struct(Link) {
     struct(MonitorLink) {
        field(pvname,string) { link}
        field(process,bool)
        field(inheritSeverity,bool)
    }
    struct(InputLink) {
         field(pvname,string) { link}
         field(pvname,string) { link}
        field(forceCA,bool)
         field(parallel,bool)
         field(parallel,bool)
         field(process,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)
         field(wait,bool)
         field(inheritSeverity,bool)
         field(inheritSeverity,bool)
     }
     }


     link(any,"StandardLinkSupport,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
Line 115: Line 135:
== dbCommon.java ==
== dbCommon.java ==
  </center>
  </center>
This file is automatically generated from dbCommon.dbd


    class LinkData {
Link support must register for each of the <tt>link</tt> definitions.
        public String pvname;
       
        public bool  forceCA;
From <tt>dbCommon.dbd</tt> the following class implementations are generated:
        public bool  parallel;
* For the link structures:
        public bool  process;
** <tt>MonitorLink</tt>, <tt>MonitorLinkData</tt>, and <tt>MonitorLinkAccess</tt>
        public bool  wait;
** <tt>InputLink</tt>, <tt>InputLinkData</tt>, and <tt>InputLinkAccess</tt>
        public bool  inheritSeverity;
** <tt>OutputLink</tt>, <tt>OutputLinkData</tt>, and <tt>OutputLinkAccess</tt>
    }
** <tt>ProcessLink</tt>, <tt>ProcessLinkData</tt>, and <tt>ProcessLinkAccess</tt>
* For TimeStamp
** <tt>TimeStamp</tt>, <tt>TimeStampData</tt>, and <tt>TimeStampAccess</tt>
* For Scan
** <tt>Scan</tt>, <tt>ScanData</tt>, and <tt>ScanAccess</tt>
 
The following shows the <tt>MonitorLink</tt>, <tt>MonitorLinkData</tt>,
and <tt>MonitorLinkAcces</tt>.
The other definitions are similar.


     public final class LinkAccess {
     public class MonitorLink implements Struct{
         public static final void get(DbfStruct dbf, LinkData data);
        public DbfString pvname;
         public static final void put(DbfStruct dbf, LinkData data);
        public DbfBool process;
        public DbfBool inheritSeverity;
         public static final int16 pvnameIndex = 1;
        public static final int16 processIndex = 2;
        public static final int16 inheritSeverityIndex = 3;
         public static final int16 lastIndex = inheritSeverityIndex;
        Dbf getField(short index) {
            switch(index) {
                case pvnameIndex: return(pvname);
                case processIndex: return(process);
                case inheritSeverityIndex: return(inheritSeverity);
                default: throw java.lang.IllegalStateException;
            }
        }
     }
     }


     class TimeStampData {
     public class MonitorLinkData (
         public long secPastEpoch;
        public String pvname;
         public int  nanoSeconds;
         public bool process;
         public bool inheritSeverity;
     }
     }


     public final class TimeStampAccess {
     public class MonitorLinkSupport implements StructFactory{
         public static final void get(DbfStruct dbf, TimeStampData data);
        public Struct create() { return new MonitorLink; }
         public static final void put(DbfStruct dbf, TimeStampData data);
         public static final void get(DbfStruct from,MonitorLinkData data) {
            DbfString dbf = from.getInterface(1);
            dbf->get(data.pvname);
            DbfBool dbf = from.getInterface(2);
            data.process = dbf->get();
            DbfBool dbf = from.getInterface(3);
            data.inheritSeverity = dbf->get();
        }
         public static final void put(DbfStruct to, MonitorLinkData data) {
            DbfString dbf = to.getInterface(1);
            dbf->put(data.pvname);
            DbfBool dbf = from.getInterface(2);
            dbf->put(data.process);
            DbfBool dbf = from.getInterface(3);
            dbf->put(data.inheritSeverity);
        }
        static {
            RegisterSupport.structure(this,"MonitorLink");
        }
     }
     }


     class ScanData {
     public final class MonitorLinkSupportRegister {
         public DbfMenu scan;
         static public createAndRegister() {
        public short phase;
            MonitorLinkSupport support = new MonitorLinkSupport;
         public DbfMenu priority;
            RegisterSupport.structure(support,"MonitorLink");
         }
     }
     }


    class ScanAccess {
        public static final void get(DbfStruct dbf, ScanData data);
        public static final void put(DbfStruct dbf, ScanData data);
    }


    // also definition for EventData and EventAccess
<bold>Question</bold> Who calls MonitorLinkSupportRegister.createAndRegister()


<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:
Line 215: Line 271:
  </center>
  </center>


Implementations of <tt>Disable</tt>, <tt>DisableData</tt>,
<tt>DisableDataSupport</tt> and <tt>DisableDataSupportRegister</tt>
are automatically generated. Their implementation is similar to
<tt>MonitorLink</tt> shown previously.
Also a definition of DisableData is generated as follows:
This file is automatically generated from iocRecord.dbd
This file is automatically generated from iocRecord.dbd
    class Disable {
        public DbfInt16 disableValue;
        public DbfInt16 disableInput;
        public DbfLink  disableLink;
        public DbfMenu  disableAlarmSeverity;
        public static final int16 disableValueIndex = 1;
        public static final int16 disableInputIndex = 2;
        public static final int16 disableLinkIndex = 3
        public static final int16 disableAlarmSeverityIndex = 4;
        public static final int16 lastIndex = disableAlarmSeverityIndex
    }


     class DisableData {
     class DisableData {
Line 237: Line 287:
     }
     }


    class DisableAccess {
Also an implementation of IocRecord is generated as follows:
        public static final get(Dbf dbf, DisableData data);
        public static final put(Dbf dbf, DisableData data);
    }


     class IocRecord {
     class IocRecord implements Struct{
         public DbfString description;
         public DbfString description;
         public DbfStruct scan;
         public DbfStruct scan;
Line 260: Line 307:
         public static final int16 processLinkIndex = 13;
         public static final int16 processLinkIndex = 13;
         public static final int16 lastIndex = processLinkIndex;
         public static final int16 lastIndex = processLinkIndex;
        Dbf getField(short index) {
            switch(index) {
                case descriptionIndex : return(description);
                ...
                case processLinkIndex : return(processLink);
                default: throw java.lang.IllegalStateException;
            }
        }
     };
     };


    public final class IocRecordFactory implements StructFactory{
        public static final Struct create() { return new IocRecord; }
    }
    public final class IocRecordFactoryRegister {
        static public createAndRegister() {
            IocRecordFactory  factory = new IocRecordFactory;
            RegisterSupport.record(factory,"IocRecord");
        }
    }
          
          
----
----
Line 274: Line 339:
     }
     }


This definition appears in the code generated from dbCommon.dbd
----
----
<center>
<center>
== iocRecordInterface.java ==
== iocRecordSupport.java ==
  </center>
  </center>


Line 283: Line 349:
functionality. This code handles processing of the following fields
functionality. This code handles processing of the following fields
of IocRecord:
of IocRecord:
; <b>disable</b>
; <tt>disable</tt>
: Decides if the record is disabled.
: Decides if the record is disabled.
; <b>alarmStatus</b> and <b>alarmSeverity</b>
; <tt>alarmStatus</tt> and <tt>alarmSeverity</tt>
: The only way to change alarmStatus and alarmSeverity is via interface Common, which is implemented by IocRecordInterface.
: The only way to change alarmStatus and alarmSeverity is via interface Common, which is implemented by IocRecordSupport.
; <b>processLink</b>
; <tt>processLink</tt>
: This is an array of process links, which replace the V3 <b>FLNK</b>
: 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.
 
===  IocRecordSupport.java ===
    enum Mode {modeNone,modeInput,modeOutput};
   
    public class IocRecordSupport extends RecordSupport, 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;
            case processIdle: {
                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 : input.init(instance); break;
                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() {
            switch(mode) {
            case modeNone: throw java.lang.IllegalStateException;
            case modeInput:
                if(requestProcess) DbAccess.process(instance);
                requestProcess = false;
                return;
            case modeOutput:
                  output.numberLinksActive--;
                  if(output.numberLinksActive==0 && requestProcess)
                      DbAccess.process(instance);
                  return;
            }
        }
        public void timedout() { 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 ===
=== Beginning of class definition ===
     enum Mode {modeNone,modeInput,modeOutput};
     enum Mode {modeNone,modeInput,modeOutput};
      
      
     public class IocRecordInterface extends RecordSupport, Callback, Common  {
     public class IocRecordSupport extends RecordSupport, Callback, Common  {
         private RecordInstance instance;
         private RecordInstance instance;
         private Mode          mode;
         private Mode          mode;
Line 302: Line 568:
      
      
         // Constructor
         // Constructor
         public IocRecordInterface(RecordInstance instance) {
         public IocRecordSupport(RecordInstance instance) {
             this.instance = instance;
             this.instance = instance;
         }
         }




IocRecordInterface implements the following interfaces:
IocRecordSupport implements the following interfaces:
; <b>RecordSupport</b>
; <tt>RecordSupport</tt>
: Record support for the fields in IocRecord.
: Record support for the fields in IocRecord.
; <b>Callback</b>
; <tt>Callback</tt>
: The callbacks called by link support
: The callbacks called by link support
; <b>Common</b>
; <tt>Common</tt>
: For now this just has the method <b>setSeverity</b>
: For now this just has the method <tt>setSeverity</tt>


It has the following private fields:
It has the following private fields:
* <b>instance</b> -  The record instance to which it is attached. <b>IocRecordInterface</b> has a single constructor which is passed the <b>RecordInstance</b> to which it is attached.
* <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.
* <b>mode</b> - This keeps the state for record processing:
* <tt>mode</tt> - This keeps the state for record processing:
** <b>modeNone</b> - The record is not being processed.
** <tt>modeNone</tt> - The record is not being processed.
** <b>modeInput</b> - The disable link is active but not complete.
** <tt>modeInput</tt> - The disable link is active but not complete.
** <b>modeOutput</b> - The processLinks are active but not complete.
** <tt>modeOutput</tt> - The processLinks are active but not complete.
* <b>input</b> - Input is a private class that provides access to the fields of disable.
* <tt>input</tt> - Input is a private class that provides access to the fields of disable.
* <b>output<b> - Output is a private class that provides access to processLink.
* <tt>output</tt> - Output is a private class that provides access to processLink.
* <b>alarm</b> - Alarm is a private class that provides access to fields alarmSeverity and alarmStatus.
* <tt>alarm</tt> - Alarm is a private class that provides access to fields alarmSeverity and alarmStatus.
* <b>requestProcess<b> - This is used by callback to decide if a request should be made to process the record.
* <tt>requestProcess</tt> - This is used by callback to decide if a request should be made to process the record.


Notes about <b>Input</b>, <b>Output</b>, and <b>Alarm</b>.
Notes about <tt>Input</tt>, <tt>Output</tt>, and <tt>Alarm</tt>.
Each of these is a private class to IocRecordInterface.
* Each of these is a private class to IocRecordSupport.
Each makes fields available to IocRecordInterface.
* 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 <b>Dbf.put</b>.
The implementations of each of these private classes is given after the implementaion of IocRecordInterface.




Line 360: Line 624:
==== process ====
==== process ====


<b>process</b> is called by dbProcess at the beginning of record processing
<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 <b>disable</b>
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 <b>processLink<./b>.
takes care of field <tt>processLink</tt>.


A few features of <b>process</b> are:
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 418: Line 682:


==== special ====
==== special ====
<b>special</b> is called when any of the fields in <b>disable</b>,
<tt>special</tt> is called when any of the fields in <tt>disable</tt>,
<b>alarmStatus</b>, <b>alarmSeverity</b>, or <b>processLink</b> are changed.
<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 463: Line 727:
      
      
=== Common methods ===
=== Common methods ===
For now the only method is <b>setSeverity,</b>
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 744:


=== Input ===
=== Input ===
This is a private class for IocRecordInterface.
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 783:


=== OutputLink and Output ===
=== OutputLink and Output ===
Output is a private class for IocRecordInterface.
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 816:
      
      
=== Alarm ===
=== Alarm ===
This is a private class for IocRecordInterface.
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 834:
     }
     }
      
      
=== IocRecordFactory ===
=== IocRecordSupportFactory ===
This is the factory for creating an IocRecordInterface.
This is the factory for creating an IocRecordSupport.
It is called by dbLoadRecords.
It is called by dbLoadRecords.


     public final class IocRecordFactory implements RecordFactor {
     public class IocRecordSupportFactory implements RecordSupportFactory{
         RecordSupport create(RecordInstance instance) {
         RecordSupport create(RecordInstance instance) {
             return new IocRecordInterface(instance);
             return new IocRecordSupport(instance);
         }
         }
         void destroy(RecordSupport support) {
         void destroy(RecordSupport support) {
             IocRecordInterface iocRecordInterface = support;
             IocRecordSupport iocRecordSupport = support;
             iocRecordInterface.destroy();
             iocRecordSupport.destroy();
        }
    }
 
    public final class IocRecordSupportFactoryRegister {
        static public createAndRegister() {
            IocRecordSupportFactory factory = new IocRecordSupportFactory;
            RegisterSupport.record(factory,"IocRecord");
         }
         }
     }
     }


Question: How does IocRecordFactory get registered?
<bold>Question</bold>
Who calls IocRecordSupportFactoryRegister.createAndRegister?

Revision as of 19:55, 31 August 2005

EPICS V4: IocRecord

August 31 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:

  1. V3 iocCore
  2. V4 Design: Record Processing
  3. V4 Design: dbdInterfaces

Unless the reader is familiar with all three, most of this document will be very difficult to understand.

Java is used as the example code for two reasons:

  1. 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.
  2. Java provides facilities that make it easy to handle strings, arrays, and structures.

An implementaion of IocRecordSupport is presented for two reasons:

  1. It demonstrates how to implement code that uses or implements the interface described in "V4 Design: dbdInterfaces".
  2. It helps refine the interfaces described in "V4 Design: dbdInterfaces".

Database Definitions

dbCommon.dbd defines the following:

    # menu definitions for dbRecordCommon 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)
        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)
        field(inheritSeverity,bool)
    }
    link(in,"MonitorLink",MonitorLink);
    link(in,"InputLink",InputLink);
    link(out,"OutputLink",OutputLink);
    link(process,"ProcessLink",ProcessLink);
    #definitions for common properties
    struct(TimeStamp) {
        field(secPastEpoch,uint64)
        field(nanoSeconds,uint32)
    }
    struct Scan {
        field(scan,menu(menuScan)) {
            special(yes)
        }
        field(phase,int16)
        field(priority,menu(menuPriority)) {
            special(yes)
        }
    }

THIS NEEDS NEW DEFINITIONS

    // ???? Does IocRecord do anything for Event
    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, MonitorLinkData, and MonitorLinkAccess
    • InputLink, InputLinkData, and InputLinkAccess
    • OutputLink, OutputLinkData, and OutputLinkAccess
    • ProcessLink, ProcessLinkData, and ProcessLinkAccess
  • For TimeStamp
    • TimeStamp, TimeStampData, and TimeStampAccess
  • For Scan
    • Scan, ScanData, and ScanAccess

The following shows the MonitorLink, MonitorLinkData, and MonitorLinkAcces. The other definitions are similar.

    public class MonitorLink implements Struct{
        public DbfString pvname;
        public DbfBool process;
        public DbfBool inheritSeverity;
        public static final int16 pvnameIndex = 1;
        public static final int16 processIndex = 2;
        public static final int16 inheritSeverityIndex = 3;
        public static final int16 lastIndex = inheritSeverityIndex;
        Dbf getField(short index) {
            switch(index) {
                case pvnameIndex: return(pvname);
                case processIndex: return(process);
                case inheritSeverityIndex: return(inheritSeverity);
                default: throw java.lang.IllegalStateException;
            }
        }
    }
    public class MonitorLinkData (
        public String pvname;
        public bool process;
        public bool inheritSeverity;
    }
    public class MonitorLinkSupport implements StructFactory{
        public Struct create() { return new MonitorLink; }
        public static final void get(DbfStruct from,MonitorLinkData data) {
            DbfString dbf = from.getInterface(1);
            dbf->get(data.pvname);
            DbfBool dbf = from.getInterface(2);
            data.process = dbf->get();
            DbfBool dbf = from.getInterface(3);
            data.inheritSeverity = dbf->get();
        }
        public static final void put(DbfStruct to, MonitorLinkData data) {
            DbfString dbf = to.getInterface(1);
            dbf->put(data.pvname);
            DbfBool dbf = from.getInterface(2);
            dbf->put(data.process);
            DbfBool dbf = from.getInterface(3);
            dbf->put(data.inheritSeverity);
        }
        static {
            RegisterSupport.structure(this,"MonitorLink");
        }
    }
    public final class MonitorLinkSupportRegister {
        static public createAndRegister() {
            MonitorLinkSupport support = new MonitorLinkSupport;
            RegisterSupport.structure(support,"MonitorLink");
        }
    }


<bold>Question</bold> Who calls MonitorLinkSupportRegister.createAndRegister()

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.

iocRecord.java

Implementations of Disable, DisableData, DisableDataSupport and DisableDataSupportRegister are automatically generated. Their implementation is similar to MonitorLink shown previously.

Also a definition of DisableData is generated as follows: This file is automatically generated from iocRecord.dbd

    class DisableData {
        public short disableValue;
        public short disableInput;
        public short disableLink;
        public DbfLink disableLink;
        public DbfMenu disableAlarmSeverity;
    }

Also an implementation of IocRecord is generated as follows:

    class IocRecord implements Struct{
        public DbfString description;
        public DbfStruct scan;
        public DbfString accessSecurityGroup;
        public DbfBool   pini;
        public DbfBool   disablePutField;
        public DbfMenu   alarmAckSeverity;
        public DbfBool   alarmAckTransient;
        public DbfBool   udf;
        public DbfStruct time;
        public DbfStruct disable;
        public DbfString alarmStatus;
        public DbfMenu   alarmSeverity;
        public DbfArray  processLink;
        public static final int16 description = 1;
        ...
        public static final int16 processLinkIndex = 13;
        public static final int16 lastIndex = processLinkIndex;
        Dbf getField(short index) {
            switch(index) {
                case descriptionIndex : return(description);
                ...
                case processLinkIndex : return(processLink);
                default: throw java.lang.IllegalStateException;
            }
        }
    };
    public final class IocRecordFactory implements StructFactory{
        public static final Struct create() { return new IocRecord; }
    }
    public final class IocRecordFactoryRegister {
        static public createAndRegister() {
            IocRecordFactory  factory = new IocRecordFactory;
            RegisterSupport.record(factory,"IocRecord");
        }
    }
        

interface Common

In addition to implementing code that handles the fields in iocRecord.dbd, iocRecord implements the following interface:

    interface Common {
        bool setSeverity(AlarmSeverity severity, string status);
    }

This definition appears in the code generated from dbCommon.dbd


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.

IocRecordSupport.java

    enum Mode {modeNone,modeInput,modeOutput};
    
    public class IocRecordSupport extends RecordSupport, 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; 
            case processIdle: {
                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 : input.init(instance); break;
                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() {
            switch(mode) {
            case modeNone: throw java.lang.IllegalStateException;
            case modeInput:
                if(requestProcess) DbAccess.process(instance);
                requestProcess = false;
                return;
            case modeOutput:
                 output.numberLinksActive--;
                 if(output.numberLinksActive==0 && requestProcess)
                     DbAccess.process(instance);
                 return;
            }
        }
        public void timedout() { 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, 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; 
            case processIdle: {
                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 : input.init(instance); break;
                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() {
            switch(mode) {
            case modeNone: throw java.lang.IllegalStateException;
            case modeInput:
                if(requestProcess) DbAccess.process(instance);
                requestProcess = false;
                return;
            case modeOutput:
                 output.numberLinksActive--;
                 if(output.numberLinksActive==0 && requestProcess)
                     DbAccess.process(instance);
                 return;
            }
        }
        public void timedout() { 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");
        }
    }

<bold>Question</bold> Who calls IocRecordSupportFactoryRegister.createAndRegister?