SecsEquip - A C++ Class for Deploying Equipment SECS Interfaces


Hume Integration has created a C++ class for rapidly deploying SEMI standard GEM compliant SECS equipment interfaces.   Without any customization, the class implements almost all of the Fundamental GEM Requirements and the Additional GEM Capabilities.  Method calls are provided for the developer to add his own Status Variables, Equipment Constants, Alarm Definitions, and Event Definitions to complement the existing items specified in the GEM standard.  The developer registers callbacks to receive asynchronous inputs such as Remote Command invocations, Terminal Display invocations, or the reception of any SECS message type of his choosing.  Other callback mechanisms are used to provide Status Variable or Equipment Constant values needed for satisfying Host requests and for sending dynamic Event Reports.

Feature Summary

GEM Compliance Statement

The software is written to conform to SEMI Standard E30 - Generic Model for Communications and Control of SEMI Equipment (GEM).  It also provides compliance to SEMI standards E5, E37, E37.1, and E10.  The software is also fully compliant with photovoltaic industry draft standard #4557 (PVEC-Interface).

The Equipment OEM developer will need to be mindful of the standard when using the Hume SecsEquip Component in order to insure that compliance is fully met.
 
 
Fundamental GEM Requirement Implemented Gem Compliant Implementation Notes
State Models Yes Yes The Communication State model is implemented by the SecsEquip and controlled by calling the CommEnable and CommDisable methods.  The current Communication State value is readable as the property, CommState. Your application receives notification of CommState and similar state changes by handling the SecsEquip StateChange event.  This event notifies you of important changes such as communication with the Host starting or ending.

Your logic and your Operator GUI affect the Control State by setting the ControlIntent and ControlMode properties. 

Comments on the Process State model follows in the next row.  Other equipment models such as Spooling are described below in this table.

Equipment Processing States Yes Yes The example application fully implements a Process State model that you can copy and modify.  Follow the example as far as posting standard GEM events for Process State changes and related events such as selecting a different Process Program.  You also need to update Status Variables to keep track of the previous and current process states, just as the example application demonstrates.
Host Initiated S1F13/F14 Scenario Yes Yes This behavior is fully provided by the SecsEquip class.
Event Notification Yes Yes Your logic needs to call the EventPost() method at the occurrence of standard collection events.  You may choose to define and report additional event types for the activities of your equipment.
On-Line Identification Yes Yes You are obligated to set the property values MDLN and SOFTREV to reflect the hardware and software configuration of the equipment.  Any change in the equipment software should result in a new unique value of SOFTREV.
Error Messages Yes Yes The standard requires use of Stream 9 Error reporting.  The SecsEquip sends specific Stream 9 messages for communication faults, conversation timeouts, incorrect device ID, unhandled message stream or function types, and non-standard data.  In the custom message handling logic that you write, use the method SendS9 to send error messages when the received message data is not in the expected format or has improper values.
Documentation Yes Yes Hume Integration has example documentation which meets requirements of the GEM and SECS standards.  This documentation is provided to Equipment providers with permission to create derivative works.

 The SECS Server has the ability to export HTML documents of the configured event, alarm, and variable table data.  You may want to use this feature of the table window that is displayed by executing the DebugTableWindow method.

Control (Operator Initiated) Yes Yes Use the demonstration application as a worked example.  The startup control state is settable using the property ControlStateStartup.  The operator choice of ON-LINE or OFF-LINE control is settable as the property value ControlIntent.  The desired substate of ON-LINE control, LOCAL or REMOTE, is settable as the property ControlMode.  The actual control state value reflects interaction with the Host and is readable as the property ControlState.  Your application receives notification of ControlState and similar state changes by handling the SecsEquip StateChange event.
ADDITIONAL CAPABILITIES      
Establish Communications Yes Yes This behavior is fully provided by the SecsEquip class.
Dynamic Event Report Configuration  Yes Yes This behavior is fully provided by the SecsEquip class.

With the capabilities that involve Status Variable values (SV) or Data Variable values (DVVAL), your job is to add equipment specific variables using the VariableAdd method.  You either provide their values through a callback using VariableMethodSet or by calling VariableSet when their values are changed.  You use the EventAdd method to define additional data collection events supported by your equipment.

Variable Data Collection Yes Yes This behavior is fully provided by the SecsEquip class. 
Trace Data Collection Yes Yes This behavior is fully provided by the SecsEquip class. 
Status Data Collection Yes Yes This behavior is fully provided by the SecsEquip class. 
Alarm Management Yes Yes This behavior is fully provided by the SecsEquip class.  Your job is to add equipment specific alarm types using the AlarmAdd method.  You use the method AlarmSet to indicate when an alarm condition is set or cleared.  You can optionally use the method AlarmEnable to enable or disable reporting of an alarm type as a Stream 5 message.  Gem also requires event reports for the Alarm Set and Alarm Clear events.  These event definitions are automatically created and managed for you by the SecsEquip when you use the AlarmAdd method.
Remote Control Yes  Yes The example application shows how to use MessageTypeAdd to receive and process Remote Commands (S2F21, S2F41, or S2F49) in your application code.   You need to implement control logic that is mindful of the Process State model and the Control State model.  For example, you need to disallow Remote Commands that affect processing when you are in the Online Local Control State. 
Equipment Constants Yes Yes This behavior is fully provided by the SecsEquip class.  Your job is to add equipment specific constants using the ParameterAdd method.  You call ParameterSet if your GUI logic or controller logic changes the value so that the SECS Server can update the ECIDChangeName GEM variable, and issue the GEM "Operator Equipment Constant Change" event.  If the host changes an Equipment Constant, you are notified via a ParameterChange event.
Process Program Management Yes Yes The SecsEquip class fully implements process program management features with upload and download capabilities.  You can set the directory used for process programs as the property RecipeDirectory.  You can set whether process program data is transferred as binary or text using the RecipesAreBinary property.  Your application is notified of process program change events by handling the SecsEquip StateChange event.   You will receive notice when recipes are downloaded from the host, uploaded to the host, or deleted by the host.  You can use these notifications to trigger validation of downloaded recipes, or you can defer validation until the time the process program is loaded for use.
Material Movement Yes Yes The GEM standard only requires that the equipment provide Data Collection events when material is sent from any port on the equipment, or received by any port, whether the transfers are automated or manual.

Automated Material Movement is implemented by calling the method MessageTypeAdd and registering a callback for each of the primary message types that the host sends.  In your callback, you parse the received SECS message data using the ListSplit and ListElement methods.  You send reply messages using the SendReply method.  You initiate your own primary messages and optionally wait for the SECS replies using the SendSecsMsg method.

Equipment Terminal Services Yes Yes The example application for the SecsEquip demonstrates displaying data received from the host, sending acknowledgment events, and sending display data to the host.  For your own implementation,  use the method TerminalDisplayAck to send acknowledgment events, and follow the example code for sending input data to the host using SendSecsMsg.
Clock Yes Yes The SecsEquip component fully implements a host-settable Clock variable value with standard data format choices.  The implementation does not affect the system clock, the host's setting is saved as an offset.
Limits Monitoring No   See the notes for Material Movement, above, to understand the general approach that is taken to implement this capability. 
Spooling Yes Yes The SecsEquip component fully implements Spooling.  We recommend that the equipment supplier only allow spooling of Alarm messages, and Event report messages or similar messages where there is no control logic tied to the receiving of the reply messages.  These are exactly the message types that most factory CIM workers want to collect with spooling.  If restricting the spooled message types is not done, there are complex issues with implementation and timing that cannot be adequately tested and verified correct.  The standard describes allowing the spooling of nearly any primary message type, out of consideration that any message may occur when the spool is being unloaded, and it should take its proper sequence at the end of the spool.  In practice this is a rare circumstance because an HSMS implementation can unload thousands of messages in a few seconds.  The downside of allowing messages that have control implications to be spooled is that they are queued for a variable and potentially lengthy delay before delivery.  The equipment provider's job is to provide a robust control system, and we think that knowing immediately that a near real-time message conversation cannot be initiated is the right choice. 

The Equipment provider can add to the message types allowed for spooling using the SpoolingAllow method.  The default behavior is to allow only Stream 5 (Alarms) and Stream 6 (Event reports) to be spooled.

Control (Host-Initiated) Yes Yes The SecsEquip class fully implements this behavior.


User Guide

After describing the Windows SecsEquip project files, we describe the POSIX SecsEquip files.

The Windows version of the SecsEquip VC++ component is provided as two Visual Studio projects, VCSecsEquip - the project for the SecsEquip class library, and VCSecsEquipApp - an example MFC application.  The SecsEquip class library is provided with source code and can be used without using the Microsoft Foundation Classes (MFC).   The SecsEquip class uses the Hume POSIX DMH client library, and a portable Pthreads library to communicate with and control the SECS server process.

Here is an overview of the project files for the Windows version:

The VCSecsEquip Project:

The VCSecsEquipApp Project: Other library dependencies with provided files: The Windows version files are distributed in a .zip archive named VCSecsEquip.zip.  If you received the DMH software on CDROM, this archive is in the subdirectory LAN_IMAGE.

The Windows version is designed and tested for Visual Studio 6.0 on Windows XP Professional, or similar up-to-date Windows Professional versions such as Windows Vista or Windows 2000 Pro.  The projects are also tested and compatible with current Visual Studio versions.

We have seen spurious problems and error messages regarding memory leaks when compiling and running in Debug mode with Visual Studio 6 on computer systems that also have the newer Visual Studio 8 installed.   Over the years Microsoft has "changed the rules" with respect to combining debug and release object code of different versions,  and has made it difficult to maintain a working VC 6 debug environment.  The software does work correctly, and is supported for use with Visual Studio 6 and newer versions including Visual Studio 2005 and Visual Studio 8.  Contact us if you need debug DLL versions for your particular Visual Studio version to avoid spurious error messages.

The POSIX version has a simpler set of project files, and the example test application is a non-windowing console application.  The files are distributed in a .zip archive file named for the platform.   The 32 bit Linux archive file is named Linux_x86_SecsEquip.zip and the 64bit Linux archive file is named Linux_x86_64_SecsEquip.zip.  Other POSIX platform versions are available.  The archives contain files in two directories:

The SecsEquip directory:

The posix_dmh directory:


Installation

Installation of the SecsEquip software consists of extracting the files in the platform specific archive to a directory of your choice, and installing the Hume Datahub SDK.  If you have already installed the Hume Datahub SDK,  you should not add the files in the SecsEquip archive to any of the existing Datahub SDK GEM application directories.  The SecsEquip class is able to find and use the Datahub SDK GEM directories without usage of a common directory.

The stored paths in the Windows .zip archive and the existing project settings and makefiles assume three peer level directories and their subdirectories.  For example, if you unzip the archive in the directory C:\hume, you will recreate our development directory structure as follows

    c:\hume\VCSecsEquip  (subdirectories Release, Debug)
    c:\hume\VCSecsEquipApp (subdirectories Release, Debug, res, recipes)
    c:\hume\posix_dmh (subdirectories pthreads, pthreads/vc6proj/Release)
 The .zip archive has some copies of the same DLL files in both the application Release and Debug directories to simplify your building and executing either the debug or release versions of the project.   The VCSecsEquip project has post-build steps that copy the freshly built DLL to the VCSecsEquipApp Debug or Release directories.  These directories should exist before this copying is attempted.

The SecsEquip VC++ software uses the SECS/GEM application files provided in the Hume Datahub SDK product.  A developer needs to install the Hume Datahub SDK, and specify on the SETUP screen that the GEM/SECS applications should be installed.  The SecsEquip component is able to find the Datahub SDK files using the environment variable DMH_BIN which is set when the Datahub SDK is installed.

The situation is simplified for a runtime deployment of your equipment SECS interface.  Instead of installing the Datahub SDK, you can simply deploy a single file executeable, SecsServer.exe.  This file is provided by Hume Integration for the usual case of using the as-provided SDK files.  If you have customized the SDK files, you are able to create a custom version of SecsServer.exe using a build script.  We encourage you to use the full SDK during development so that you have the toolset documentation, the debugging tools, and you are able to view the SDK GEM application source code.  When you are ready for deployment, you can download the SecsServer.zip archive from the Hume customer support website to obtain the SecServer.exe program and its build script.

Installing the POSIX version is similar to the Windows version.  You can unzip the archive in a convenient directory of your choice.  You face the same choice of using the files with either the Datahub SDK installed, or with the SecsServer executable for your platform.  You need to make sure the environment variable DMH_BIN is set and exported if the Datahub SDK is being used.  The environment variable described below should be set for all platforms.

Environment Variable SECS_EQUIP_TCLDIR

When a SecsEquip instance is constructed, it needs to find the Datahub SDK files or the SecsServer executable file.  The startup logic looks for the SecsServer file in the current working directory, and then it tries one or two directory levels up, which is a common development scenario when an executable is run from the subdirectory Debug or Release.   If the SecsServer executable is not found then the startup logic searches for the SecsServer.tcl file in the gem2/server or gem/server directories of the Datahub SDK installation found using the environment variable DMH_BIN or the default SDK install path.  Alternately, you may set the environment variable SECS_EQUIP_TCLDIR to the directory path containing the SecsServer executable or the SecsServer.tcl application script.  This gives you the ability to deploy the executables with whatever directory structure you desire.  Use slash directory separators on all platforms.  On Windows, environment variables are set by navigating from the Start menu - Start/Settings/Control Panel/System/Advanced/Environment Variables.  An example value is:
SECS_EQUIP_TCLDIR=C:/usr/local/gem/server
In a runtime deployment, the SecsServer executable file is placed in the directory of your choice as specified by the SECS_EQUIP_TCLDIR environment variable.   A licenses.txt file is also installed in this directory.  You can execute the SecsServer program from the command line with the single argument -license to perform a check of the runtime license installation.  The default directories used for process program transfer and for non-volatile storage are subdirectories of where the SecsServer or SecsServer.tcl file is found.

On POSIX systems, the SecsServer executable does not use X-Windows if the DISPLAY environment variable is either not defined, or defined to be an empty string.   This gives you the capability of executing without being tied to any display.

Development

To start using the Hume VC++ SecsEquip class with an existing Visual Studio project, its probably easiest to add the entire VCSecsEquip project as a subproject and indicate that it is a dependency for your application.

The SecsEquip software uses the Hume POSIX DMH library internally to control the SECS interface server using the Hume DMH message system.  You may want to explore using the DMH message for your own application requirements such as integrating your User Interface with Controller systems, intelligent devices, and instruments.

Your primary focus as a developer is using the class SecsEquip.  This class implements public methods to send and receive SECS messages, and manage an equipment SECS interface.

Here is the general flow of using and configuring a SecsEquip instance:

  1. Setup your error handler callback first by setting the SecsEquip::SecsServerErrorCallback static pointer item.  Your application may receive error notifications if the license or software installation are not proper when you try to instantiate a SecsEquip instance.  Therefore, have the error handling in place first so you can provide the user notification of any errors.
  2. Construct a SecsEquip instance.  When the SecsEquip instance is constructed, it spawns a SECS Server process.  On Windows, the SECS Server uses DDE to determine what other Tcl/Tk applications are running.  You need to construct a SecsEquip instance under conditions where your application will respond to DDE unless you disable the DDE usage by setting the environment variable NO_DDE_QUERY to the value of 1.  We have found that MFC applications do not respond to DDE while executing the OnInitDialog virtual function.  The example application demonstrates a small workaround - a timer event is initiated from the OnInitDialog method, and then the SecsEquip construction and initialization are done in the timer handler after the OnInitDialog method returns.
  3. Set the callback pointer for StateChange events.  Once the next step is taken, your callback is executed to provide you with initial values of state data.  In general the callbacks are executed from different threads than the starting thread that created your window controls.  Its not documented very clearly, but for most of the method invocations, window controls are not designed to be used by different threads than the main event-dispatching thread of your application.  The safest course is to copy the techniques in the example application in the use of PostMessage to notify the main thread.
  4. Use saved user configuration data to know the desired HSMS connection properties such as the socket port and whether the active or passive role is desired.  Call ConnectTypeHsmsPassive() or ConnectTypeHsmsActive() to set the connection type.  When the connection type is set, the SECS server creates a data array and table records for the SECS interface.  Some of the other configuration method calls require the table records or array being present.  So a ConnectType call should be made early in the initialization.  Its ok to call a ConnectType method with default argument values, and later in the initialization, make another ConnectType call with other argument values.  The important point is to make the ConnectType call early.
  5. Now you can perform the bulk of your SECS interface configuration.  Do the following, in any order:
  6. Programmatically you can set the desired Control State properties and then call CommEnable to enable host communications.  You probably want to offer configuration dialogs and make the desired startup configuration of the Contol State and whether communication is enabled or disabled be user specified and persistent.
  7. Call CommDisable to disable host communications.  It is called automatically in the SecsEquip destructor method.

Tcl Secs Notation, TSN

SECS messages are passed into and out of the application as formatted strings.  The format is similar to the notation in the SEMI documents except that the list formatting conventions of the Tcl programming language are followed.  The SecsEquip API provides methods to split, join, append, and extract list elements.  In general, curly braces, { }, are used to surround list elements which contain white space.  By using the API calls to append list elements or join strings as list elements, you can be sure that your strings are properly formatted, and you do not need to manually balance opening and closing curly braces.  Developers who have worked with both XML and TSN list notation have found that the TSN notation is more compact, closer to the SEMI documentation, and easier for a human to scan and validate when reviewing diagnostic output.

As general guidance, when you expect a string value, you will get a two element list, of the form "A:n {this is n chars of text}".  If a string value does not have imbedded white space, it may be formatted without braces, such as "A:8 OneToken".  When you use the ListElement or ListSplit methods to parse the text, they take care of parsing and removing surrounding braces for you.  If an empty string is sent, you will see a one element list, A:0.  SECS has the notion of array data - 0 or more values of a given type.  When you expect to receive a single numeric value, you receive a two element list, with the type code as the first element, such as "U4:1 290".  You can also receive an empty array "U4:0" or an array with more than one value as in "U4:3 0 1 2".  Binary data values are formatted using C-language hexadecimal integer notation, for example, "B:3 0x00 0x01 0x02".  You can use the BinToInt method to convert these values to integer values.  With received data, the type code has a length value appended to it after a colon.  With data that you format for sending, the length information is optional, the data is parsed to determine the length.  See the TSN.html document for more details.
 
Semi Octal type code TSN type code Meaning & Examples
00 L List,  L, L:0,   "L {A {atc 100}} {A 1.0.0}", "L:2 {L:2 {U4 200} {U4 210}} {B 0}"
10 B binary - unsigned 8 bit data, "B 0", "B 1 2 3"
11 TF  boolean data, TSN type codes BL or BOOLEAN are also accepted as input, "TF 1"
20 A Character string data.  Traditionally this has meant printable ASCII characters but some implementations are sending any 8 bit characters including nulls using this type.
"A {hello world}", "A hello"
21 J Japan International Standard (JIS-8) encoded text.  This format is not commonly used or supported because in the past the SEMI standards have failed to identify specific reference documents.
22 V1..VE Variant data, also known as Localized Character Strings.  Your VC++ unicode text is automatically converted into the chosen encoding.  V1 is for Unicode 2.0, V2 is for UTF-8 encoding.  See the TSN.html document for more details. "V1 {sent as Unicode}"
30 I8 8-byte signed integer, "I8 -1"
31 I1 1-byte signed integer, "I1 -3"
32 I2 2-byte signed integer, "I2 99",  "I2 15 -7 99"
34 I4 4-byte integer signed, "I4 -5"
40 F8 8-byte floating point, "F8 6.02e23", "F8 0.1"
44 F4 4-byte floating point, "F4 1.0"
50 U8 8-byte unsigned integer, "U8 0"
51 U1 1-byte unsigned integer, "U1 0"
52 U2 2-byte unsigned integer, "U2 512"
54 U4 4-byte unsigned integer, "U2 979"

 

Built-in SECS Data, Message Handling, Events

The SecsEquip class has built-in logic to handle more than 85 of the standard SECS message types.  You do not have to code or provide for complex GEM capabilities such as dynamic event reports, or the communication and state models.  See the reference table for more detail on the built-in message types.

Similarly, the variables required for GEM compliance are already defined, and are listed in the built-in variables table. In some cases, such as the PPExecName variable, your custom application logic has to provide current data values.  The example application demonstrates using the VariableSet method or the VariableMethodSet method as techniques to supply variable values.  If a data item's value is changed infrequently, its more efficient to use VariableSet which provides the current value to the SECS server process.  The VariableMethodSet method is the right choice for data items whose value changes more often, or are easier to manage as VC++ application data items.

The SecsEquip software uses type U4 numeric identifiers for the numeric IDs called out by GEM such as ALID, CEID, ECID, and SVID.  These identifiers are passed as unsigned, 4 byte integers - SEMI Octal code 54.

 There are also some standard event report types specified by GEM and pre-defined for you as listed in the built-in events table. Your application logic needs to call EventPost as these events and your own defined events occur during processing.
 

Custom SECS Message Handling

Use the method MessageTypeAdd to have SECS messages routed to your callback code for custom handling.  Your callback executes in a different thread than your main Windows event dispatching thread so use thread safe techniques for accessing application data or GUI controls.  The positive side of using a different thread is that your handling logic can be coded to use simple synchronous wait-for-reply SECS conversations without locking up your GUI.  For example, your callback can use SendReply to respond to the inbound message, and then initiate a synchronous conversation using SendSecsMsg and specifying that the logic should wait for the reply message.  While your handling code is progressing through the synchronous conversation, other software in your application can be making method calls to report events, or alarms.  Because of the internal design of the SecsEquip, these other method calls are not blocked or delayed because your handler is busy with a conversation.

Logic in your application can send SECS messages or initiate conversations using the SendSecsMsg method.  For HSMS communication,  if you are sending a message and not waiting for the reply, SendSecsMsg can be used from your GUI code without fear of making your GUI unresponsive.  In some cases you need to wait for a SECS reply message.  If you are using HSMS, under most circumstances, the host's reply or failure to reply will be resolved within a few seconds.   The unusual circumstance is that you still have a TCP/IP connection to the host so your send is successful, but then the host does not reply, and you wait the full T3 period.  You can code your logic so that if the host does not respond to any message, you transition to offline control so subsequent message sends fail right away because they are not appropriate in an offline control state.  So with this change, you risk making the GUI unresponsive for a single T3 period in some unusual circumstances.  If this risk is not acceptable, you can create a new thread, and use the new thread to perform the SECS conversation where you need to wait for the reply message.

Miscellaneous Notes

Your design will typically use one instance of a SecsEquip component to provide a single SECS interface.  You can use multiple instances of the class to provide more than one SECS interface.  Each interface can have its own custom handling of message types.  The Equipment OEM can also provide more than one SECS equipment interface to support multiple factory host applications if provision is made for coordinating control.  The latter can be as simple as telling every interface except one that the equipment is under local control.  This provides the benefits of the newer EDA standards without the complexity of implementing additional protocols.

SecsEquip Class Reference


 SecsEquip Properties
Property Access Description
static DMHClient dmh SecsEquip instances use a shared connection to the DMH message system in order to communicate with the SECS server process.  The connection instance, dmh, is public in case you want to access it in your application.  Since it is shared (static) the access is SecsEquip::dmh.
bool getAlarmsShareEvents(void)

void setAlarmsShareEvents(bool)
Set this property value true to have the same AlarmDetected and AlarmCleared data collection events reported for any alarm type.  The preferred value of this property should be set before calling the AlarmAdd() methods.  The behavior preferred by the Photovoltaic Industry Draft Standard #4557 is to have the value set true and to share generic events.  The default value of the property is false to preserve compatibilty with existing applications.
int getBAUD(void)
void setBAUD(int BAUD)
This property sets the baudrate of the serial port for the SECS-I, RS-232 connection type.  The default value is 9600.
const char *getCommState(void) Read-only value of your GEM Communication State.  Possible values are DISABLED, ENABLED {NOT COMMUNICATING}, and COMMUNICATING.   The StateChange event is used to obtain asynchronous notification of this property value change.
const char *getControlIntent(void)
void setControlIntentOnline(void)
void setControlIntentOffline(void)
Your intended GEM Control State behavior, whether your equipment is in the OFF-LINE or ON-LINE control state.  The default setting is OFF-LINE.
const char *getControlMode(void)
void setControlModeRemote(void)
void setControlModeLocal(void)
When in ON-LINE control, your intended substate of LOCAL or REMOTE control.  Defaults to LOCAL.
const char *getControlState(void) Read-only, your actual GEM Control State which reflects your ControlMode, ControlIntent and host dynamics.  Possible values are ON-LINE LOCAL, ON-LINE REMOTE, OFF-LINE Equipment, OFF-LINE Host, and OFF-LINE SeekOnline.  These string values are enumerated in the SecsEquip::ControlStateText string array, in the same order as ControlStateEnum values.  The StateChange event is used to obtain asynchronous notification of this property value change. 
ControlStateEnum getControlStateStartup(void)
void setControlStateStartup(ControlStateEnum e)

// control state values
 enum ControlStateEnum { OfflineEquipment=0,   OfflineAttemptOnline=1, OfflineHost=2, OnlineLocal=3, OnlineRemote=4};

Your software is able to specify the initial state for the GEM Control State model.  The choices are:  OfflineEquipment, OfflineAttemptOnline, OfflineHost, OnlineLocal, or OnlineRemote.  This setting defaults to OfflineEquipment, but is overruled to be consistent with your ControlIntent and ControlMode values.  If your ControlIntent is OFF-LINE, and your startup is an Online state, the startup state is changed to OfflineEquipment.  If your ControlIntent is ON-LINE and your startup state is OfflineEquipment, your startup state is changed to OfflineAttemptOnline.  Similarly the setting of ControlMode can overrule an online startup state corresponding to the opposite LOCAL or REMOTE online substate choice.  This logic is applied when CommEnable is called.
int getDEVID(void) 
void setDEVID(int DEVID);
The SECS Device ID.  An identifier imbedded in SECS header data usually left at the default of 0.  You can change it anytime but you are better off setting it before enabling communication.  Per the standard, the SecsEquip rejects messages from the host that are not for the equipment's Device ID.  Settable range is 0..32767.
static char * SecsEquip::DmhGroupName The DMH message system groupname used by the SECS server.  The same groupname should be specified to the constructor of every SecsEquip instance in the application in order to share the same SECS server process.
bool getHSMS(void)
void setHSMS(bool HSMS)
Whether the Connection type is HSMS (LAN based).  False implies SEC-I, serial RS-232 communication.  Defaults to true.
const char *getHSMS_Host(void) 
void setHSMS_Host(const char *h);
For an active HSMS connection, specifies the TCP/IP hostname or IP address of the Host computer.
bool getHSMS_Passive() 
void setHSMSPassive(bool p)
For an HSMS connection, whether the SecsEquip plays the passive, TCP/IP server role.  The default value is true which is the usual role of equipment. 
int getHSMS_Port() 
void setHSMS_Port(int p)
For an HSMS connection, the TCP/IP socket port number.  Defaults to 5555.
bool getIdRangeChecked()
void setIdRangeChecked(bool b)
By default, the methods to add Alarm, Event, Variable, and Parameter definitions, restrict the numeric ID values allowed to ranges which prevent you from colliding with built-in values, or colliding with each other's values.  However, the range checking can be disabled by setting this property value false.  Also, you can renumber the built-in events and variables, and customize the events that are assigned for alarm set and clear events.  Thus, you are able to completely customize the identifiers used by the SECS interface.  If you choose to renumber and customize the identifiers, do it in your initialization logic before enabling communication, but after restoring or configuring the connection type.  This insures that connection instance data exists in the SECS server to hold your customization.
const char *getMDLN() 
 void setMDLN(const char *mdln)
The SECS Equipment Model Type - limited to no more than 6 characters by the E5 standard.



bool getMULT(void)
void setMULT(bool MULT)
For SECS-I serial connections - when this property is true, multiple open transactions are allowed.  When true, a new message may be sent requesting a reply before the host has replied to a previous message.   The flag is only for SECS-I, and the default value is true. 
 
HSMS host implementations should not have a problem with multiple open transactions.   However, there are factories with deficient software who would rather compromise the standards than fix their bugs.  If you get into a customer support situation with HSMS and multiple open transactions, please contact us - we have a lightweight go-between application that queues and serializes the open transactions.
const char *getName() The SecsEquip name passed to the constructor and used in the SECS server process as a Tcl command name, a global array name, and an identifier in SQL table records.
bool getParametersAreSaved()
void setParametersAreSaved(bool ParametersAreSaved)
This property controls whether the values of parameters (Equipment Constant Variables) are saved at the program exit and restored during the next session.  Saving the values is standard GEM behavior so the default value is true.  If the value is true, the saved values are restored the first time that CommEnable is called, unless it has been already restored by calling the method ParametersRestore.  In other words, you can use the method ParametersRestore to force loading of the saved values before CommEnable is called.   The value data is saved as a file of SQL statements in the subdirectory spooldata.  The filename used is "EcvParms_" + Name + ".sql".
bool getRecipesAreBinary()
void setRecipesAreBinary(bool RecipesAreBinary)
A boolean flag to indicate whether Process Program files should be transferred as type B (binary) data, or type A (ASCII) data.  The default is true, meaning binary transfer.  If Process Program files are printable text, the type A transfer is easier for the factory personnel to work with.  The software is able to transfer binary data as type A but not all host software can accommodate this.
const char *getRecipeDirectory() 
void setRecipeDirectory(const char *RecipeDirectory)
A pathname to the file system directory where Process Program files are located.  The default is "./recipes" - a subdirectory of the current working directory.
bool getReportsAreSaved()
void setReportsAreSaved(bool ReportsAreSaved)
This property controls whether the state of event reporting is saved at the program exit and restored during the next session.  Saving the state of dynamic reporting is standard GEM behavior so the default value is true.  If the value is true, the saved event reporting configuration is restored the first time that CommEnable is called, unless it has been already restored by calling the method ReportsRestore.  In other words, you can use the method ReportsRestore to force loading of the saved reporting configuration before CommEnable is called.   The report configuration data is saved as a file of SQL statements in the subdirectory spooldata.  The filename used is "reportdata_" + Name + ".sql".
int getRTY(void)
void setRTY(int RTY)
SECS-I retry count.  This value specifies the maximum number of send retry attempts for block transmission.  The default value is 3 with an allowed range of 0..31.
bool isS13InUse()
void setS13InUse(bool b)
This boolean property chooses whether to enable using Stream 13 large process program transfer message types when an online control state exists.  In addition to the Stream 13 messages, this property also enables or disables using S7F29, S7F37, S7F38, S7F41, and S7F42 which are used with Stream 13 for transferring large unformatted, process programs.  The default value is false. Stream 13 message types are preferred for transferring large data sets because the data is split into multiple smaller messages which require less memory use.  If Stream 13 message types are enabled, per GEM your application should implement sending S7F27 process program verification messages for  received process programs.
const char *getSerialPort(void)
void setSerialPort(const char *SerialPort)
For a SECS-I connection, the serial port device such as "COM1".
const char *getSOFTREV() 
void setSOFTREV(const char *softrev)
The SECS Software revision - limited to no more than 6 characters.  Default value is "1.0.0".  You may wish to consider a pattern of major.minor.patchlevel.
const char *getSpoolingAllow() 
void setSpoolingAllow(const char *SpoolingAllow)
This property is set to specify the streams which the host is allowed to specify for spooling in message type S2F43.  It is formatted as a space separated list of "S<s>" tokens where the <s> value is stream number.  The standard does not allow Stream 1 to be spooled.  The default value is "S5 S6" which allows for spooling alarm messages and event reports.  An empty string value disallows any spooling.  The value only affects the handling of S2F43 messages from the host.  Your software is able to change at any time which message types are being spooled using the method, SpoolStreamFns.
const char *getState() A read-only value of the low-level connection state.  Possible values include OFFLINE, LISTENING, and COMMUNICATING.  You will see the OFFLINE state if the connection to the host is broken.  The StateChange event is used to obtain asynchronous notification of this property value change.
int getT1(void)
void setT1(int millisecs)
SECS-I Inter-Character Timeout in milliseconds, range 100..10000, default 500
int getT2(void)
void setT2(int millisecs)
SECS-I Protocol Timeout in milliseconds, range 200..25000, default 10000
int getT3(void)
void setT3(int millisecs)
SECS Reply Timeout in milliseconds, range 1000..120000, default 45000
int getT4(void)
void setT4(int millisecs)
SECS-I Inter-Block Timeout in milliseconds, range 1000..120000, default 45000
int getT5(void)
void setT5(int millisecs)
HSMS Connect Separation Timeout - the delay between re-connection attempts in milliseconds, range 1000..240000, default 10000
int getT6(void)
void setT6(int millisecs)
HSMS Control Transaction Timeout in milliseconds, range 1000..240000, default 5000
int getT7(void)
void setT7(int millisecs)
HSMS Not Selected Timeout in milliseconds, range 1000..240000, default 10000
// int getT8(void)
// void setT8(int millisecs)
HSMS Network Intercharacter Timeout, default value 5000.  This value is not used.
int getTRACE(void) 
void setTRACE(int trace)
Used as a bitfield to control diagnostic trace information for SECS port activity which is passed to the application in the SecsTrace event.  By setting specific bits, the corresponding output is turned on. 

General Tracing: (TraceType = trace) 
Bit        Output Description 
0x0001     Read and write calls
0x0002     state changes including connection attempts 

Receive Tracing: (TraceType = rtrace) 
Bit        Description for Received Messages 
0x0100     Header binary dump 
0x0200     Header interpretation 
0x0400     Stream and Function description
0x0800     Message data binary dump 
0x0004     The Message as TSN 

Send Tracing: (TraceType = strace) 
Bit        Description for Sent Messages 
0x1000     Header binary dump
0x2000     Header interpretation
0x4000     Stream and Function description
0x8000     Message data binary dump
0x0008     The Message as TSN 

RcResult setTraceSaving(bool save, bool compress, int maxDayFiles, const char *saveDir = NULL, const char *zipCmd = NULL)

typedef struct _RcResult {
 int rc;  // return code
 char *result;
} *RcResult;

bool isTraceDataSaved()

bool isTraceDataCompressed()

const char * getTraceSaveDir()

int getTraceSaveMaxDayFiles()

const char *getTraceSaveZipCmd()

The toolset software has the configurable feature of continuously saving the SECS communication trace data to files - one file per day, up to a maximum number per year, and optionally compressing the closed file from the previous day shortly after midnight.  The setTraceSaving method is used to reconfigure the logging feature with the various properties being set atomically in one call. The saving logic writes each day's output to a distinct file, in the directory named by the saveDir argument.  The maxDayFiles argument controls how many day files are saved per year.  It can be configured between 1 and 366.  When file saving is initiated, the output filename is set to traceNNN.txt where the NNN value is the current day of the year, 0 to 365, modulo the maxDayFiles value.  If this file already exists and has been written to earlier in the same day, then the output is appended to it, otherwise the file is created as a new file. Note that if the maxDayFiles value is set to 1, each day's output is saved to the same filename, trace000.txt.  The default values provide for saving the data from each connection in a separate directory.  Separate directories are required for each connection.  When trace data is being written, the compress argument controls whether the logic attempts to compress the output file when it is closed at the end of the day (midnight).  For compression to occur, the maxDayFiles value must be greater than 1 and a non-blank compression command must exist as the zipCmd argument.  The default assignment of zipCmd is similar to zip.exe -m tracetxt.zip. This command causes the data file from the previous day to be moved into the tracetxt.zip archive, creating the archive if it does not exist.   The compression logic appends the day file name to the configured command before execution.  Only trusted persons should be allowed to configure the compression command because of the security considerations. 

The RcResult return value of setTraceSaving() is used as follows.  If the rc value is less than 0 the arguments were not acceptable and an error message is provided as the result String.  If the rc value is 0, the call succeeded.  If the rc value is greater than 0, the call succeeded with an advisory message as the result String.  For example, a message occurs if compression is set true but there is a maximum of only 1 file, so there is no distinct file for the previous day to compress. 

Memory is allocated from the heap for the RcResult, and it must be freed by calling Free() when the caller is done with it.

int getTracewinMaxWidth(void)
void setTracewinMaxWidth(int ctChars)
The approximate maximum number of characters to display in a single line of the trace window.  This value guards against excessive data use when long messages such as recipe transfer occur and the trace window is displaying connection activity.  Range 1000..120000, default 4000.


 
SecsEquip Events
Event Handler and Argument Data  Description


All event handlers - NOTES
 
 
 
 
 

 

With the VC++ SecsEquip class library, callback pointers are used to pass event invocations into your application.  The callback functions need to be static functions, and you need to use ClientData arguments or pointers to class instances if you want to execute method calls of objects.  The example application demonstrates these techniques.  As noted earlier, the thread that executes your callback is not your main GUI thread, and you need to use threadsafe programming techniques.
typedef void (SecsParameterChangeProc)(SecsEquip *, const char *varname, const char *newvalue);

 // just set your own function address to receive the events
 SecsParameterChangeProc *ParameterChangeCallback;
 

This event notifies you of host initiated Equipment Constant Variable (ECV) changes.  The new value is within the limits you have configured.
typedef void (SecsMessageReceiveProc)(SecsEquip *, int stream, int function, bool send_reply, 
  int transactionID, const char *TSN_data, const char *header, void *clientData);
See the MessageTypeAdd method described in the next section to see how to receive SECS messages in your application.  This mechanism is demonstrated for Remote Commands and for Terminal Services in the example application.
typedef void (SecsServerErrorProc)(const char *errorInfo);

static SecsServerErrorProc *SecsServerErrorCallback;

The SecsEquip class reports Tcl programming errors that are trapped in the SECS Server process as SecsServerError events.  An example would be trying to send an improperly formatted SECS message.  These error events will happen during development but should be rare once the code is debugged.
typedef void (SecsTraceProc)(SecsEquip *, const char *traceType, const char *text);

// just set your own function address to receive the events
 SecsTraceProc *SecsTraceCallback;

This event provides you with the detailed information of SECS message traffic that is viewed in the SECS Trace window.  The information is controlled by setting the TRACE property.
typedef void (SecsSpoolingAlertProc)(SecsEquip *, const char *msgid);

SecsSpoolingAlertProc *SpoolingAlertCallback;

The GEM standard describes Spooling events that are to be brought to the attention of the equipment operator.  The msgid values include SPOOLING_ACTIVATED, SPOOLING_FULL, SPOOLING_TERMINATED, SPOOLING_NOT_PERSISTENT, and SPOOLING_DATA_DISCARDED.  See example explanation messages in the application.  The latter two values are not seen in normal circumstances.
typedef void (SecsStateChangeProc)(SecsEquip *, const char *varname, const char *newvalue);

SecsStateChangeProc *StateChangeCallback;

This event notifies your application of state value changes. Possible varname values include 
  • state - the State property value changed
  • clock_offset - this value is the number of seconds added to the system clock to provide CLOCK variable values for the host.  If the value differs from 0, the host has used S2F31 to set the clock.  Your logic can work with host specified time values by adjusting the system time using this offset value, or by reading the CLOCK variable using VariableGet().  We recommend that you avoid this complexity by instructing your customers to use NTP time synchronization and that you disable S2F31 using MessageTypeRemove().
  • comm_state - the CommState property value changed
  • control_state - the ControlState property value changed
  • dataset_download - a process program has been downloaded from the host using Stream 13 transfer messages.  The newvalue argument is a two item list, the ppid, and the pathname to the newly received file.  Use the ListSplit or ListElement method to parse the list.  See the discussion of downloaded files in the description of method ProcessProgramLargeRequest.
  • dataset_upload - a process program was successfully transmitted to the host using Stream 13 transfer messages.  The newValue argument is the ppid.
  • event - this value changes when a data collection event is posted either by your logic calling the EventPost method, or by the built-in SECS server logic.  The newvalue argument is a two item list, the CEID of the event, and a 1 or 0 indicating whether an event report message was sent or not.  A report is not sent or spooled if communication is disabled, or if the event type is disabled, or if the control state is offline.  Also, when spooling is active, the event report may not be spooled.
  • recipe_delete - the name of a recipe that is being deleted by the host, or being replaced with a downloaded version using Stream 7 messages.
  • recipe_download - the name of a recipe that has just been received from the host using Stream 7 messages.
  • recipe_upload - the name of a recipe that has just been uploaded to the host using Stream 7 messages.
  • spooling_state - the SecsEquip spooling state, ACTIVE or INACTIVE
  • SpoolCountActual - the number of SECS messages currently spooled
  • SpoolCountTotal - the total number of messages spooled and/or discarded
  • SpoolMax - the configured maximum number of spooled messages
  • SpoolStreamFns - the list of S<s>, S<s>F<f> message types that configured for spooling
Your application gets notified of the initial values of these items when the SecsEquip connection type is initialized.

SecsEquip Methods
METHOD DESCRIPTION
General Comments
 
 

 

The List manipulation methods are actually implemented by the POSIX dmh.dll, and exposed for your convenience by the SecsEquip class.
void AlarmAdd(int ALID, const char *ALTX)

void alarmAdd(int ALID, const char *ALTX, int alarmSetCEID, int alarmClearCEID)

Add an alarm type definition. Newly created alarms are enabled.  The first form is the commonly used choice for new SECS interfaces where the CEID's for the GEM Alarm events are configured automatically.   Depending on the setting of the AlarmsShareEvents property, the GEM alarm set and clear data collection events will either be the same events shared by all alarm types, or two new events will be created for each alarm type.  Set your preferred value of AlarmsShareEvents before using the AlarmAdd methods.

If the AlarmsShareEvents property is true, use only the first form of AlarmAdd where the set and clear event IDs are not specified.  Use any ALID value from 1000 to 3999.  If the AlarmsShareEvents property is false, choose only even numbers for the ALID from 1000 to 3998  to allow for two enabled events which are created for each alarm, an alarm set event with CEID == ALID, and an alarm clear event with  CEID == ALID+1.

The ALTX argument is a description of the alarm and it has a length limit of 40 ASCII characters.  The ALTX should not contain single quote characters.

The second form of AlarmAdd() lets you specify the CEID values used for the Alarm Set and Clear event reports.  Use this form if you need to customize which data collection events are posted for the alarm's Set and Clear events.  If the event types do not already exist, they are created.  There is no validation performed on the specified CEID values, they only need to be representable as 4 byte unsigned integers.   With this form of AlarmAdd you are able to specify any ALID value from 1000 to 3999 with the default range restriction in place.

With either form, you are able to bypass the usual range restriction of the ALID value by setting the property IdRangeChecked false.

void AlarmEnable(int ALID, bool is_enabled) Enable or disable reporting of an Alarm type (S5F1).
bool AlarmIsEnabled(int ALID) Test if the reporting of an alarm type is enabled 
bool AlarmIsSet(int ALID) Test if the alarmed state is currently set
void AlarmSet(int ALID, bool is_set) Set or Clear the alarmed state of an alarm.
int BinToInt(const char *binValue)

 

Converts a SECS B (Binary  - Semi "10") data value usually formatted as a hexadecimal string to an integer value.
void CommDisable(void) Disable SECS communication.  The SecsEquip is initialized without communication enabled so using this method only makes sense after CommEnable has been called.
void CommEnable(void) Enables SECS communication.  The CommState property value will change and StateChange events will be received.  These changes are the asynchronous indications for success or failure to establish communication.  When your equipment is configured for the Active HSMS role, field personnel will want to display the trace window with the 0x0002 TRACE property bit set in order to see detailed information on the status of communication attempts. 
int ConnectTypeHsmsActive(const char *host_or_ip, int port) This method is an alternative to setting the underlying property values to specify an active HSMS connection type, and calling ConnectTypeSet().  Communication should be disabled when the connection type is set.
int ConnectTypeHsmsPassive(int port) This method is an alternative to setting the underlying property values to specify a passive HSMS connection type, and calling ConnectTypeSet().  Communication should be disabled when the connection type is set.
int ConnectTypeSerial(const char *serialPort, int baudrate)
This method is an alternative to setting the underlying property values to specify a SECS-I connection type, and calling ConnectTypeSet().
int ConnectTypeSet(void) This method is called to use the current property values and initialize a SECS interface for the indicated connection type.  It is called by the ConnectType<Type> methods.  If you are setting connection property data directly, call this method after your property values are set.  The method returns the value 0 to indicate success.
void DebugDMHStatus(bool show) This method causes the DMH message system status window to either be shown or dismissed.
void DebugInspect() This method can be used to exec the Inspect introspection debugger.
void DebugTableWindow(bool show) This method causes the Datahub table management GUI to be shown or dismissed. 
void DebugTclConsole(bool show) This method causes a console window for the SECS Server to be shown or dismissed.
void DebugTraceWindow(bool show) This method is used to display a window which updates to show SECS message traffic and state information for the SecsEquip.   There are menu options to control the data displayed, and menu actions to save the displayed data to the file system.  This method invokes the Tcl version of the Trace window which is created by the SECS Server process.  The example application features the SecsTracewin class and instantiates a native VC++ window with similar function.  Including the VC++ window in the administration area of your equipment GUI is desirable to help field personnel diagnose communication problems. 
void EventAdd(int CEID, bool is_reported, const char * description, optional const char *eventName = NULL) This method is used to create an Event type.  With the default range checking of ID values, you are restricted to use CEID values between 5000 and 9999 so you do not collide with Alarm Set and Clear events, or the built-in events.  You can set the IdRangeChecked property false if you need to customize the assigned IDs.  Events can be given meaningful names, and the names can be used when posting event occurrences.  Choose names that are less than 32 characters and consist of alphanumeric characters and/or the hyphen or underscore.  If the eventName argument is not provided, the name defaults to the CEID value formatted as a string.  A specified  event name value should be unique among all of the event names for the SecsEquip instance..
void EventEnable(int CEID, bool is_enabled) Event reports are enabled for an event type when first created.  You can use this method to control whether an event report is enabled.
bool EventIsEnabled(int CEID) Test if reporting of an event type is currently enabled.
void EventPost(int CEID)

void EventPostByName(const char *eventName)

These methods are used to announce when an event has occurred.   In general, make sure that the data items that the host might want in an event report are set to their proper values before EventPost is called.  You should make this call without testing to see if reporting of the event is enabled and without other testing of the communication or control states. The two method forms allow for posting the event by its CEID or its name.
int EventRenumber (const char *eventName, int newCEID) This method is provided so that the CEID values of the built-in events can be customized.  Use the method after restoring or configuring the connection type, and before enabling communication.  If the newCEID value is in use by a different event, that event is given a "temporary" ID value of the current value plus 1 million under the assumption that it will be renumbered as well.  After initialization, if events are found with ID values greater than 1 million, they indicate that more than one event has been assigned to the same ID value. 

A positive return value is a warning, and the value 0 indicates success.  In more detail, the return values and their meanings are:

0
The event already has the desired ID, or the event was renumbered successfully.
1
The new ID was in in-use so the existing event was renumbered to a "temporary" ID.
2 or more
The return value is the number of events of this name that were found.  The extra table records were deleted and the surviving table record has the desired ID or was renumbered successfully.  This condition is not ordinarily expected.
Exception
If the eventName does not identify an existing event an exception is thrown.  Also, if the method does not succeed from an unexpected error such as a timeout, an exception is thrown.  The data passed when the exception is thrown is a char * string describing the problem.
void Free(void *data) This method must be called to free allocated memory that is passed to the application as the result of calling
  • ListElement
  • ListJoin
  • ListSplit
  • ParameterGet
  • ProcessProgramDownload
  • ProcessProgramLargeRequest
  • ProcessProgramLargeSend
  • ProcssProgramUpload
  • QuoteDouble
  • SendSecsMsg
  • SendSecsMsgRcResult
  • ServerSQLReply
  • ServerTclReply
  • TclReply
  • TclReplyRcResult
  • VariableGet
char *ListAppend(const char *tclList, const char *e1, const char *e2 = NULL,  const char *e3 = NULL, const char *e4=NULL, const char *e5=NULL, const char *e6=NULL); This method is used to add one to six list elements to text that is formatted as a Tcl list.  It is a good programming practice to use ListAppend or ListJoin to build a Tcl list, in order to make sure that imbedded white space or other special characters are properly delimited with curly braces or escaped with backslashes.  An empty string may be passed as any of the element argument values, in order to represent an empty list or empty element.  The first NULL argument indicates the previous argument is the end of the list.

Memory is allocated from the heap for the result, and it must be freed by calling Free() when the caller is done with it. 

char *ListElement(const char *tclList, int index1, int index2=-1, int index3=-1); This function is similar to the lindex function of Tcl.  It will parse text formatted as a Tcl list and return the specified element.  Indexing starts from 0.  Arguments index2 and index3 may be used to indicate that parsing of the TclList should continue up to two additional levels as a nested list structure. If a specified index is out of bounds, an empty string is returned.  Not all strings are valid Tcl lists.  If an invalid list is parsed, NULL is returned. 

Memory is allocated from the heap for the result, and it must be freed by calling Free() when the caller is done with it.

char * ListJoin(int argc, const char * [] argv); Joins together strings as Tcl list elements forming a result string that is a Tcl list.  Braces are added as needed to delimit empty elements, or to delimit special Tcl character sequences involving backslashes , square brackets, etc. 

Memory is allocated from the heap for the result, and it must be freed by calling Free() when the caller is done with it.

int ListSplit(const char *TclList, int *argc, char **argv[]) ListSplit( ) parses a string formatted as a Tcl list into an array of string elements.  The function understands the Tcl usage of quotes, braces and backslash sequences.  Not all strings are valid Tcl lists. The return value is 0 on success. Failure occurs when there are unmatched braces, unmatched quotes, or non-whitespace following braces or quotes.

Memory is allocated from the heap for the resulting argv[] stack and the elements that the stack points to. The argv result must be passed to dmh_free() to reclaim the allocated memory when the caller is done with it.

void MessageTypeAdd(int stream, int function, SecsMessageReceiveProc *callback,   void *clientData = NULL);)

typedef void (SecsMessageReceiveProc)(SecsEquip *, int stream, int function, bool send_reply, 
  int transactionID, const char *TSN_data, const char *header, void *clientData);

Call this method to have SECS messages processed by your custom handler methods when the SecsEquip is in online control, and the message is received from the host.  You can provide for new SECS message types, or you can replace the existing SecsEquip handling of particular messages.  Use the SendReply, SendS9, and SendAbort methods to send reply messages. You can use the clientData argument to pass a pointer to an application object or data structure into the receiving handler.
void MessageTypeRemove(int stream, int function) This method is used to cancel SECS message handlers that you have setup using MessageTypeAdd or to cancel the handling of particular messages during the online control state by the built-in SecsEquip logic.  For example, you may wish to turn of Process Program management message types for a tool that does not use Process Programs.  If you have called MessageTypeAdd for the specified message type, the Add is cancelled.  If you have not called MessageTypeAdd, the SECS server is told not to handle the message. Unhandled messages are replied to with an abort reply.  If the unhandled message does not ask for a reply, an S9F5 message is sent to indicate an unknown function.
void ParameterAdd(int varID, const char *varname, const char *description, const char *value_TSN, const char *initialValue, const char *minValue, const char *maxValue, const char *defaultValue, const char *units) This method is used to add Equipment Constant Variable definitions (ECVs).  With the default range checking active, use varID values that are between 1000 to 2999.  Use a unique value for each parameter.  The value_TSN argument is the Tcl SECS notation type code for the ECV value such as F4 for floating point, or A:80 for an ASCII string up to 80 characters long.  Call ParameterSet when the ECV value is changed by your GUI or controller logic so that the SECS Server can manage the appropriate GEM event.  With ASCII types, indicate the maximum number of characters, n, that you wish to allow the host to set, by using a type code of the form A:n.  The value of n can be as large as 60000.

If you have custom ID requirements, you can set the IdRangeChecked property false to disable varID range checking, and you can renumber existing Parameters and Variables using the VariableRenumber method.

char *ParameterGet(int varID) This method is used to get the current value of an ECV.  It uses the same access logic that host requests use so it can test your custom value logic.  The return value is NULL if there is an error.

Memory is allocated from the heap for the result, and it must be freed by calling Free() when the caller is done with it.

int ParameterSet(int varID, const char *newvalue) This method is used to update the value of an ECV whose current value is represented in the ei_variable table.
void ParametersRestore() Restores the saved values of the parameters (Equipment Constant Variables).  The ParametersRestore() method gets called automatically when you first enable communication if property ParametersAreSaved is true, and ParametersRestore() has not already been called.  The call restores the values of parameters from the last session, and it initializes saving for the current session. There is logic so that restoring only occurs once.  It is useful to make this call if you want to force the restore action to occur before communication is enabled.  For example, this could support viewing the current values of the parameters before communication is enabled.  The connection type should be set and all of the parameters should be defined before calling this method.
RcResult ProcessProgramDownload(const char *ppid) 

typedef struct _RcResult {
 int rc;  // return code
 char *result;
} *RcResult;

Used by the equipment to initiate the download of a process program from the host using S7F5.  The ppid argument value is both the process program identifier and the file name that is used by the equipment for the process program file.  There is no standard SECS command for the equipment to know what process programs are available from the host for downloading.  The return value is a pointer to an allocated structure containing an integer return code and a result string.  If the return code value is 0 which indicates success, the result string is the full pathname to the process program file.  Negative return code values indicate error.  Possible errors include those described with SendSecsMsg().  In addition the following error codes are also possible:  -10 file system error, -11 improper data received, -12 request denied by the host. In the case of error, the result string is a diagnostic message.

Memory is allocated from the heap for the result, and it must be freed by calling Free() when the caller is done with it.

RcResult ProcessProgramLargeRequest(const char *ppid) 

typedef struct _RcResult {
 int rc;  // return code
 char *result;
} *RcResult;

This method initiates the download of a process program from the host using the message types of Stream 13 which are designed for large data set transfers.  Using these messages is more complex than the usual Stream 7 transfer messages so they are less commonly supported.  The ppid argument value is both the process program identifier and the file name that is used by the equipment for the process program file. There is no standard SECS message for the equipment to know what process programs are available for download.  The return value is a two element structure, a return code and text.  The return code is 0 if the transfer is initiated successfully as determined by the host's reply to S7F41.  The transfer is not complete when the method returns.   The large data set transfer logic receives the downloaded file in the subdirectory, dataset_transfer, of the directory set by the RecipeDirectory property.  When the transfer is complete, there is a StateChange event with the name dataset_download and the newvalue being a two element list consisting of the ppid value and the full pathname to the newly received file.  To fully comply with the large process program transfer scenarios specified by GEM E30, your application should react to the StateChange event by verifying the newly received process program and sending the S7F27 Process Program Verification message to the host using SendSecsMsg.  The S7F27 message is sent with replyIsWanted true, but there is no reason to wait for the host's reply.  After verification, your application can move the file into the RecipeDirectory for use, possibly overwriting an earlier version.

If the transfer does not complete successfully, there is additional status information is the SECS server table ei_dataset_xfer.   It is possible to query this table or subscribe to data changes of this table to better integrate transfer status information.

Possible error results include values of the ACKC7 reply to S7F41 and the following:
1 permission not granted
4 PPID not found
6 other error
-6  error when sending S7F41 or receiving the S7F42 reply
-13 PP transfers are disabled when spooling is active
-14 A large PP receive is already in progress for ppid
-15 Stream 13 transfers are disabled either from configuration or initialization failure
-16 PPID is not usable as a restricted filename
-17 error when parsing the S7F42 reply

Memory is allocated from the heap for the result, and it must be freed by calling Free() when the caller is done with it.
RcResult ProcessProgramLargeSend(const char *filename) 

typedef struct _RcResult {
 int rc;  // return code
 char *result;
} *RcResult;

This method initiates the upload of a process program to the host using the message types of Stream 13 which are designed for large data set transfers.  Using these messages is more complex than the usual Stream 7 transfer messages so they are less commonly supported.  The filename argument value is both the process program identifier and the file name that is used by the equipment for the process program file.  The return value is a two element structure, a return code and text.  The return code is 0 if the transfer is initiated successfully as determined by the host's reply to S7F37.  The transfer is not complete when the method returns.   The large data set transfer logic makes a temporary copy of the file for transfer in the subdirectory, dataset_transfer, of the directory set by the RecipeDirectory property.  This allows your application to change or access the process program while the copy is being transferred.  When the transfer is complete, there is a StateChange event with the name dataset_upload and the newvalue being the filename value.   If the transfer does not complete successfully, there is additional status information is the SECS server table ei_dataset_xfer.   The SECS Server also posts UploadSuccess, UploadTimeout, and UploadFailure data collection events that can be monitored as StateChange events with the name event.

Possible error results include values of the ACKC7 reply to S7F37 and the following:
1 permission not granted
6 other error
-4  PPID filename not found
-6  error when sending S7F37 or receiving the S7F37 reply
-13 PP transfers are disabled when spooling is active
-14 A large PP receive is already in progress for ppid
-15 Stream 13 transfers are disabled either from configuration or initialization failure
-16 error copying the PPID for large send
-17 error when parsing the S7F38 reply

Memory is allocated from the heap for the result, and it must be freed by calling Free() when the caller is done with it.
RcResult ProcessProgramUpload(const char *ppid) 

typedef struct _RcResult {
 int rc;  // return code
 char *result;
} *RcResult;

Used by the equipment to initiate transferring a process program to the host using S7F3.  The ppid argument value is identically the file name of the process program and the identifier for the process program.  The return value is a pointer to an allocated structure containing an integer return code and a result string. The return code value is 0 for complete success.  Negative return code values indicate an error.  Possible error values include those possible with ProcessProgramDownload().  In addition, the return code value of -13 is used to indicate "upload disabled during spooling".  A positive return code value is the SECS standard ACKC7 code value sent by the host.  Diagnostic text is provided in the result string for all return code values. 
Important:  Do not assume that the host saves process program files with the same file names or in the same format that the equipment does.  The only proper way to use an uploaded process program file is to download it using the same host software that uploaded it.
Memory is allocated from the heap for the result, and it must be freed by calling Free() when the caller is done with it.
char *QuoteDouble(const char *text); This method returns a result string where instances of single quotes in the input string are doubled.  This is the escaping method used by SQL. Memory is allocated from the heap for the result, and it must be freed by calling Free() when the caller is done with it.
void ReportsClear() This method erases any existing event report definitions, unlinks the event reports from event types, and disables the event reports that were linked to the deleted reports.  The call also deletes any saved event report data, so it can be used to prevent or nullify the restoring of event reports from the previous saved session.  The method is not usually called since saving and restoring the dynamic event report configuration is standard GEM behavior.
void ReportsRestore() ReportsRestore gets called automatically when you first enable communication if property ReportsAreSaved is true, and ReportsRestore has not already been called.  The call restores the state of event reporting from the last session, and it initializes saving for the current session.  Restoring overwrites the existing event report definitions.  There is logic so that restoring only occurs once.  A connection type should be set and the variables and event types should be defined before calling this method.
void SecsEquip() 

void SecsEquip(const char *spname, const char *dmhGroup)

The class constructor.  The spname argument becomes the name of a global data item and a Tcl command in the SECS Server process.  It needs to be unique for each SecsEquip instance, and not coincide with a keyword in the Tcl programming language.  The default value of spname is similar to SecsEquip0.  The example application uses the spname value, gemsim.  The name should be a single alphanumeric token. 

The dmhGroup argument becomes the DMH message system group name used by the SecsEquip and SECS Server process.  If you are instantiating more than one SecsEquip instance in your process, construct each instance using the same dmhGroup name argument so that the SECS Server process is shared.  The groupname chosen needs to be unique among other DMH server instances on the computer where the SecsEquip is executing.  The default value is GEM.  This value does not conflict with the default value for Hume Datahub instances which is mbx.  The name should be a single alphanumeric token. 

The SecsEquip SECS Server process can be debugged remotely by connecting to the DMH mailbox SERVER_RPC@hostname:dmhGroup using the Inspect application or using the DMH mailbox SERVER_SQL@hostname:dmhGroup by the hubclient application.

void SendAbort(int stream, int primaryFunction) This method is used to send an F0 abort message in lieu of a proper reply.  It is used to indicate that the received message is not appropriate in the current context.   For example, when the control state is ON-LINE LOCAL, the abort reply should be sent to a host message that would affect processing.
void SendReply(int stream, int function, int transactionID, const char * TSN_data = "") This method is used by your custom SECS message handling logic to send reply messages either with or without data.  The reply data is formatted as Tcl Secs Notation text.
void SendS9(int function, const char *header) This method is used to indicate an error condition response to a received message - it is sent in lieu of a normal reply.  The SecsEquip software takes care of many of the possible error conditions automatically, including, 1- bad Device ID, 3 - bad stream, 5 - bad function, and 9 - T3 timeout.  You will not receive a message type, unless you register for it.  Therefore, you will mostly send the function value 7 to indicate improper data.
char *SendSecsMsg(int stream, int function, bool reply_wanted, const char *TSN_data, bool wait4reply)
 

RcResult SendSecsMsgRcResult(int stream, int function, bool reply_wanted, const char *TSN_data, bool wait4reply)

typedef struct _RcResult {
 int rc;  // return code
 char *result;
} *RcResult;
 
 
 
 
 
 
 
 
 
 
 
 

 

These methods are used to send a primary SECS message, optionally indicating a reply is wanted, and optionally indicating that the call should wait for a reply.  The methods differ in how the return value data is presented.  The SendSecsMsg() return value is a string which is structured as a two element list consisting of an integer return code and a string result.  The string result is typically parsed with the ListElement(), or ListSplit().  The SendSecsMsgRcResult() returns a pointer to the same data already parsed into a structure that has an integer return code and a result string.  In both cases, the return value must be deallocated using a single call to the Free() method.   The possible return values are:
-1
errorMessage  - the error message starts with "ERROR" and describes the fault
-2
DISABLED   - communication is disabled so the message could not be sent
-3 
OFF-LINE   - the control state is OFF-LINE and per GEM only S1F1, S1F13, and S9FX are sendable.
-4 
DISCARDED   - spooling is active and this message type is not spooled.  Usually the connection is down.  But this result can also occur for a newly established connection before the host has purged or finished unloading the spool.
-5 
BUSY   - an eq_send call is currently active.  You should not see this error, since by design send commands are serialized using DMH messages to the connection's command mailbox.
SPOOLED    Your message has been spooled for later sending.  Even if you specify waiting for the reply result you receive this instead of the reply data if the message is spooled.  We recommend you not allowing spooling of message types where you care about the reply.
SENT_NO_REPLY  - sent successfully no reply requested
SENT_NO_REPLY_WAIT  - sent successfully, a reply was indicated, not waiting for the reply was indicated.  The reply will be ignored when it arrives.
ReplyTsnData   -sent ok, reply requested and received.
-6 
TIMEOUT  - sent ok, reply requested, no reply, T3 timeout. 
-7 
ABORTED  - sent ok, F0 abort reply received.
-8 
REJECTED  - sent ok, Stream 9 error message "reply".

Remember to call Free() with the reply result when you are done using it.  You are able to Free() the RcResult in a single call because the data pointed to by the result pointer is contained in the same memory allocation as the _RcResult structure.

static void ServerSQLCmd(const char *sql) Send an SQL command to the SECS Server process without waiting for a reply.  This method is used by the SecsEquip software and made public in case of custom requirements.
static char *ServerSQLReply(const char *sql) Send an SQL command to the SECS Server process and wait for the reply.  This method is used by the SecsEquip software and made public in case of custom requirements.

Memory is allocated from the heap for the result, and it must be freed by calling Free() when the caller is done with it.

static void ServerTclCmd(const char * tclCommand); Send a Tcl command to the SECS Server process without waiting for a reply.  This method is used by the SecsEquip software and made public in case of custom requirements.  After a SecsEquip instance has been constructed and the connection type set, the TclCmd( ) method should be used instead of this method for commands that are directed to a particular interface instance.  Why?  Doing so serializes the commands for a particular interface, and provides re-entrant execution protection.
static char *ServerTclReply(const char *tclCommand); Send a Tcl command to the SECS Server process and wait for the reply message.  This call is used by the SecsEquip software and made public in case of custom requirements.  After a SecsEquip instance has been constructed and the connection type set, the TclReply( ) method should be used instead of this method for commands that are directed to a particular interface instance.

Memory is allocated from the heap for the result, and it must be freed by calling Free() when the caller is done with it.

void SpoolPurge(void) This method discards any spooled messages that are queued for the host.
void SpoolStop(void) This method sets the messages types that are enabled for spooling to an empty string, thus, further spooling is stopped.
void SpoolStreamFns(const char *StreamFns = NULL) The method is used to set the spooled message types.  If called with no arguments, the streams that are allowed for the host to enable (property SpoolingAllow) are enabled.  If called with an argument, the call bypasses the SpoolingAllow property and enables spooling for the S<s> and S<s>F<f> message types that are specified in the input string.
void TclCmd(const char *tcl) This method is used to send Tcl code to the SECS server command mailbox for the connection.  It is used by the SecsEquip software and made public to support custom requirements.
char *TclReply(const char *tcl)

RcResult TclReplyRcResult(const char *tcl)

typedef struct _RcResult {
 int rc;  // return code
 char *result;
} *RcResult;

These methods are used to send Tcl code to the SECS server command mailbox for the connection and wait for the evaluation result.  They are used by the SecsEquip software and made public to support custom requirements.  With TclReply() the string return value is structured as a list and may be parsed using ListSplit or ListElement.  The first element is a return code for the evaluation with 0 meaning success.  The second element is the return value from the executed Tcl code, or an error message if the return code is not 0.  With TclReplyRcResult( ) the same data has been parsed and is returned as separate fields in an allocated data structure.

Memory is allocated from the heap for the result, and it must be freed by calling Free() when the caller is done with it.

void TerminalDisplayAck() Calling this method posts the data collection event named TerminalServicesOperatorAck which is used by the equipment to indicate acknowledgment of a host Terminal Display.
bool TsnTypeIsOk(const char *value_TSN) This method is used to check value_TSN argument values that you pass to the various Add methods.
void VariableAdd(int varID, const char *varname, const char *description, const char *varClass, const char *value_TSN, const char *varmethod, const char *initialValue, const char *units) Use this method to add a Status Value variable (varClass == "SV") or a Data Value variable (varClass == "DVVAL").  Both classes of variables are available for the host to configure in event reports.  A DVVAL does not need to have a valid value, for example the alarm ID of the latest alarm when there have been no alarms.  With the default checking of Id values, use varID values between 3000 and 9999.  Leave the varmethod argument as NULL or an empty string if the variable value will be represented in the ei_variable table, or you will subsequently call VariableMethodSet to specify an evaluation callback. 

If you have custom ID requirements, you can set the IdRangeChecked property false to disable varID range checking, and you can renumber existing Parameters and Variables using the VariableRenumber method.

char * VariableGet(int varID) This method is used to get the current value of a variable.  It uses the same access logic that host requests use so it can test your custom value logic.  The return value is NULL if there is an error.

Memory is allocated from the heap for the result, and it must be freed by calling Free() when the caller is done with it.

int VariableRenumber (const char *varname, int newID) This method is provided so that the ID values of the built-in variables and parameters (ECVs)  can be customized.  All of these data items are represented in the same table, and should be given unique numeric identifiers.  Use the method after restoring or configuring the connection type, and before enabling communication.   If the newVarId value is in use by a different variable, that variable is given a "temporary" varID value of the current value plus 1 million under the assumption that it will be renumbered as well.  After initialization, if variables are found with ID values greater than 1 million, they indicate that more than one variable has been assigned to the same ID value. 

A positive return value is a warning, and the value 0 indicates success.  In more detail, the return values and their meanings are:

0
The variable already has the desired ID, or the variable was renumbered successfully.
1
The newVarId was in in-use so the existing variable was renumbered to a "temporary" ID.
2 or more
The return value is the number of variables of this name that were found.  The extra table records were deleted and the surviving table record has the desired ID or was renumbered successfully.  This condition is not ordinarily expected.
Exception
If the varname does not identify an existing variable an exception is thrown.  Also, if the method does not succeed from an unexpected error such as a timeout, an exception is thrown.  The data passed when the exception is thrown is a char * string describing the problem.

void VariableSet(int varID, const char *newValue) This method is used to update the value of a Status Value or Data Value variable whose current value is represented in the ei_variable table.
void VariableMethodSet(int varID, SecsVarValueProc *callback)

typedef const char *(SecsVarValueProc)(SecsEquip *, int varID);

You use this method to register a callback that is executed by the SecsEquip software when the value of a Status or Data Value variable is needed.  The callback is executed by a different thread than your main GUI thread, so be sure to use threadsafe programming techniques such as mutexes.  See the application example.

If the callback argument value is NULL, then any existing callback is unregistered, and the variable method is changed so that the value is managed in the ei_variable table using the VariableSet() method.


Built-in Features

The table of contents link in the frameset viewer shows the SECS Equipment Built-in Features document for this section. Having a separate document shared with the multiple Equipment libraries helps us provide you with more accurate, detailed information.

License Terms

Subject to Change Without Notice

The Hume C++ SecsEquip software is licensed for development and runtime use at no additional charge for computers that are licensed for development use of the Hume Integration Datahub SDK.

Hume Integration is also pleased to offer separate runtime licenses for using the SecsEquip software on systems that are not licensed as development systems.  Contact Hume Integration for information on the Resale Licensing program.


Document Version

Date of last revision: $Date: 2014/02/05 21:06:33 $