====== TransSECS Host: StartupTrigger ====== ===== 1. StartupTrigger Purpose ===== The **StartupTrigger** script is a TransSECS host-side initialization script, written in JavaScript for the embedded Java/Nashorn engine. It is responsible for: * Initializing the host-to-tool SECS/GEM connection. * Configuring the database connection ( if needed) * Registering a listener for connection status changes. * Ensuring the tool is in the `ToolStatus` database table (If need as in the example) * Logging system parameters. * Preventing redundant setups with flags. ===== 2. A Generic Host StartupTrigger Code Example ===== // === Generic Host StartupTrigger === // Java Imports var TransSecsController = Java.type("com.ergotech.transsecs.secs.TransSecsController"); var ConnectionStatusListener = Java.type("com.ergotech.transsecs.secs.host.ConnectionStatusListener"); var SimulationManager = Java.type("com.ergotech.util.SimulationManager"); var DataSource = Java.type("com.ergotech.vib.servers.DataSource"); var ValueChangedEvent = Java.type("com.ergotech.vib.valueobjects.ValueChangedEvent"); var Thread = Java.type("java.lang.Thread"); var LinkedHashMap = Java.type("java.util.LinkedHashMap"); var System = Java.type("java.lang.System"); // Global Config with defaults (properties read from ErgoTechConfiguration.properties) testingStr = System.getProperty("testing","0"); testing=parseInt(testingStr,10); toolID=System.getProperty("toolid","fix_the_toolid"); toolName=System.getProperty("toolname","fix_the_tool_name"); lotTable = toolID + "LotHistory"; waferTable = toolID + "WaferHistory"; loadPortsStr=System.getProperty("loadports","2"); loadPorts = parseInt(loadPortsStr,10); // For Reference (ConnectionStates) /* ENABLE_ALL_EVENTS_FAILED(-80), ENABLE_EVENTS_FAILED(-70), LINK_REPORTS_FAILED(-60), CREATE_REPORTS_FAILED(-50), ENABLE_ALARMS_FAILED(-40), ONLINE_FAILED(-30), COMMUNICATION_FAILED(-20), CONNECT_FAILED(-10), DISCONNECTED(-1), OPERATIONAL(0), CONNECTED(10); */ function listenerSetup() { simulationManager = SimulationManager.getSimulationManager(); simulationState = simulationManager.getCurrentSimulationState(); DataSource.logMessage("Simulation state is " +simulationState); onlyOnce= /Devices/UtilityServers_Servers/ConnectionListenerSetup->getIntValue(); if (!simulationState && onlyOnce==0) { try { /Devices/UtilityServers_Servers/ToolId->setStringValue(toolID); /Devices/UtilityServers_Servers/ToolName->setStringValue(toolName); /Devices/UtilityServers_Servers/ConnectionListenerSetup->setIntValue(rnd); DataSource.logMessage("StartupTrigger: host initialization started"); host = TransSecsController.getSingleController(); count=0; while (host == null) { count++; Thread.sleep(50); host = TransSecsController.getSingleController(); } DataSource.logMessage("Startup Trigger: Host model is ready, rnd="+rnd); DataSource.logMessage("StartupTrigger: Setting database connection configuration for rnd="+rnd); Thread.sleep(200); userName=System.getProperty("dbusername","username"); password=System.getProperty("dbpassword","password"); ipaddress=System.getProperty("dbAddress","dbaddess"); dbName=System.getProperty("dbName","dbname"); portStr=System.getProperty("dbPort","1433"); port=parseInt(portStr, 10); DBManager="/Devices/DatabaseConnection"; DBManager-->setUrl("jdbc:sqlserver://" + ipaddress + ":"+port+";databaseName="+dbName); DBManager-->setUsername(userName); DBManager-->setPassword(password); DBManager-->setDriverClassName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); DataSource.logMessage("StartupTrigger: DatabaseConnection url is "+ DBManager-->getUrl()); initializedValue=/Devices/UtilityServers_Servers/Initialized->getIntValue(); dbServer = "/Devices/DatabaseConnection"; count=0; while ((dbServer-->isRunning()==false)) { Thread.sleep(500); count++; if (count % 20 === 0) { DataSource.logMessage("TransSECS needs to be toggled to LIVE to continue"); } } DataSource.logMessage("StartupTrigger: DatabaseConnection is running: "+dbServer-->isRunning()); Thread.sleep(100); DataSource.logMessage("StartupTrigger: Continuing application initialization..."); try { DataSource.logMessage("StartupTrigger: Checking if tool " + toolName +" exists in ToolStatus database ..."); if (!(toolName.contains("fix_the_toolname"))) { existsSQL="SELECT ToolId from FAB_ISS.dbo.ToolStatus WHERE ToolName='"+toolName+"'"; dbError=1; while (dbError==1) { Thread.sleep(200); try { /Devices/DatabaseConnection_Servers/CheckToolStatus->setSQLStatement(existsSQL); result=/Devices/DatabaseConnection_Servers/CheckToolStatus->retrieveValueObject(); dbError=0; } catch ( e ) { DataSource.logMessage("StartupTrigger: error getting result of checking tool in toolstatus table"); DataSource.logMessage("error "+e); DataSource.logMessage("StartupTrigger: waiting another 200 ms for the db connection"); dbError=1; } } if (result.size()==0) { DataSource.logMessage("StartupTrigger: First time INSERT of tool "+toolName); insertNewTool(toolID, toolName, lotTable, waferTable, loadPorts); } } else { DataSource.logMessage("StartupTrigger: Error: toolname parameter is not configured."); } } catch (e1) { DataSource.logMessage("StartupTrigger: Error adding new tool to ToolStatus: " + e); DataSource.logMessage(e.printStackTrace()); } DataSource.logMessage("StartupTrigger: setting up connection status listener, rnd="+rnd); var connectionStatusListener = new ConnectionStatusListener() { connectionStatusChanged: function(connectionStatus, comment) { DataSource.logMessage("ConnectionStatusListener: Connection Status Changed: " + comment + "(" + connectionStatus + ")"); /Devices/UtilityServers_Servers/CheckDatabaseConnection->setIntValue(connectionStatus); dbStatus=/Devices/UtilityServers_Servers/DatabaseOK->getIntValue(); if (dbStatus!=0) { vo = new StringValueObject("StatusUpdate"); map = new LinkedHashMap(); map.put("ToolStatusCode", new StringValueObject(connectionStatus)); map.put("ToolStatus", new StringValueObject(comment)); vo.setProperty("MAP", map); /Devices/UtilityServers_Servers/UpdateToolStatusTable->valueInput(new ValueChangedEvent(this, vo)); } if (connectionStatus==10) { DataSource.logMessage("ConnectionListener: SECS/GEM connection established to tool."); } else if (connectionStatus==0) { DataSource.logMessage("ConnectionListener: GEM Host configuration to tool completed."); } else if (connectionStatus<0) { DataSource.logMessage("ConnectionListener: WARNING: Connection issue detected: "+comment); } } }; if (host != null) { onlyOnce = /Devices/UtilityServers_Servers/ConnectionListenerSetup->getValueObject(); existing = onlyOnce.getProperty("Listener"); if (existing != null) { try { host.removeConnectionStatusListener(existing); } catch (err) { DataSource.logMessage("StartupTrigger: Exception removing listener" + err); } } onlyOnce.setProperty("Listener", connectionStatusListener); /Devices/UtilityServers_Servers/ConnectionListenerSetup->setValueObject(onlyOnce); host.addConnectionStatusListener(connectionStatusListener); DataSource.logMessage("StartupTrigger: Connection Status Listener registered with host"); } else { DataSource.logMessage("StartupTrigger: host is null, connection status listener not set up"); } DataSource.logMessage("StartupTrigger: Updating ToolStatus table for "+toolName); vo = new StringValueObject("StatusUpdate"); map = new LinkedHashMap(); map.put("ToolStatusCode", 0); statusString = "Tool IP Address:\"" + host.getEquipmentHostName() + "\" Port:"+host.getActivePort()+" Device ID:"+host.getDeviceId(); map.put("ToolStatus", statusString); vo.setProperty("MAP", map); /Devices/UtilityServers_Servers/UpdateToolStatusTable->valueInput(new ValueChangedEvent(this, vo)); } catch (e) { DataSource.logMessage("StartupTrigger Error: Problem in configuration setup"); DataSource.logMessage(e.stack); } } } // Setup a new tool in the ToolStatus table function insertNewTool(id, toolName, lotTable, waferTable, ports) { DataSource.logMessage("StartupTrigger: Inserting new tool: " + id); for (var p = 1; p <= ports; p++) { var portToolID = id + "_0" + p; var sql = "INSERT INTO FAB_ISS.dbo.ToolStatus (ToolId, ToolName, LotHistoryTable, WaferHistoryTable, Port) " + "VALUES ('" + portToolID + "', '" + toolName + "', '" + lotTable + "', '" + waferTable + "', '" + p + "')"; /Devices/DatabaseConnection_Servers/InsertToolStatus->setSQLStatement(sql); try { /Devices/DatabaseConnection_Servers/InsertToolStatus->executeStatement(); DataSource.logMessage("StarupTrigger: Inserted tool: "+toolName+ " and port:"+p +" into ToolStatus table"); } catch (e) { DataSource.logMessage("Startup Trigger: Insert of "+toolName+ " into ToolStatus table failed: " + e); } } } ///////////////////// MAIN SCRIPT ///////////////// if (incomingValue.getQuality()==0) { random = new java.util.Random(); rnd = random.nextInt(999999); print("Startup Trigger MAIN Entry rnd="+rnd); toolInitialized = false; /Devices/UtilityServers_Servers/Initialized->setIntValue(toolInitialized); DataSource.logMessage("StartupTrigger: Initializing "+toolName +"("+toolID+") rndID="+rnd); /Devices/UtilityServers_Servers/CheckDatabaseConnection->setStringValue("StartupTrigger:Main"); var r = new java.lang.Runnable() { run: function() { listenerSetup(); } }; new Thread(r).start(); toolInitialized = true; /Devices/UtilityServers_Servers/Initialized->setIntValue(toolInitialized); } incomingValue; =====3. Section-by-Section Breakdown ===== **1. Global Setup** Reads config properties (toolID, toolName, loadports) from `ErgoTechConfiguration.properties`. **2. Main Trigger Entry** If `incomingValue.getQuality() == 0`: * Logs startup. * Generates random `rnd`. * Clears `Initialized` flag. * Runs `listenerSetup()` in a separate thread. * Sets `Initialized` to 1. **3. listenerSetup()** * Checks simulation mode and whether listener already exists. * Stores ToolId, ToolName, and marks listener setup. * Waits for Host availability. * Configures DB connection. * Ensures tool is in ToolStatus table. * Sets up and registers a connection listener. * Updates ToolStatus table with initial status. **4. insertNewTool()** * Inserts a row per load port into ToolStatus. ===== Notable Safety Mechanisms ===== ^ Feature ^ Purpose ^ | Simulation check | Avoids DB/config setup in simulation | | ConnectionListenerSetup | Prevents multiple listener registration | | Initialized flag | Prevents repeated initialization | | Thread for listenerSetup | Avoids blocking VIB thread | | Retries & logging | Ensures DB and host readiness | ===== Where to Put the Script ===== 1. Right-click **project name** → “Add Devices”. 2. Right-click **Devices** → “Add UtilityServers”. 3. Right-click **UtilityServers** → “Add StartupTrigger”. 4. In the **Script** box, uncheck “set script value to null” and paste this script. 5. Save project, build, and go live.The startupTrigger will be working when the system is startup. {{:screenshot_2025-08-14_151042.png?400|}}