File size: 22,967 Bytes
f6f4993
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
<!DOCTYPE html>
<!--
================================================================================
  FILE: 02_utility_functions.html
  PURPOSE: Documents the UTILITY FUNCTIONS used throughout the script.
           These are building blocks called by the higher-level configuration subs.

  FUNCTIONS COVERED:
    - CreateLogFile      (line 202)  — creates the LogFile script in Starter
    - PrintToLogFile     (line 219)  — appends text to the LogFile script
    - SetParam           (line 228)  — writes a parameter to a drive object and logs it
    - Padding_Text       (line 251)  — pads a string to a fixed width for aligned log output
    - PrintHeader        (line 270)  — writes a table header row to the log file
    - SetSym             (line 299)  — writes a symbol (named alias) to a drive object and logs it
    - ConfirmWithUser    (line 343)  — shows a Yes/No popup dialog
    - GoOnline           (line 348)  — takes the Starter project online or offline
    - CheckExists        (line 704)  — checks if a device/TO object exists in the project
    - EchoToScreen       (line 2382) — prints a message to the HTML status bar
    - StatusLine         (line 2394) — sets text/colour of a step's status cell
    - StatusLineEcho     (line 2399) — StatusLine + EchoToScreen combined
================================================================================
-->
<html>
<head>
  <meta charset="UTF-8">
  <title>02 — Utility Functions | Siemens Configurator</title>
  <style>
    body      { font-family: Arial, sans-serif; background: #f5f5f5; color: #222; margin: 20px; }
    h1        { color: #003366; border-bottom: 3px solid #003366; padding-bottom: 6px; }
    h2        { color: #005599; margin-top: 30px; }
    h3        { color: #007733; }
    pre.code  { background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 6px;
                font-family: Consolas, monospace; font-size: 13px; overflow-x: auto;
                border-left: 4px solid #569cd6; white-space: pre-wrap; }
    .comment  { color: #6a9955; }
    .keyword  { color: #569cd6; }
    .string   { color: #ce9178; }
    .number   { color: #b5cea8; }
    .note     { background: #fff8dc; border: 2px solid #f0c040; border-radius: 6px; padding: 12px; margin: 10px 0; }
    .explain  { background: #e8f5e9; border: 2px solid #4caf50; border-radius: 6px; padding: 12px; margin: 10px 0; }
    .warn     { background: #fff3e0; border: 2px solid #ff9800; border-radius: 6px; padding: 12px; margin: 10px 0; }
    nav       { background: #003366; padding: 10px; border-radius: 6px; }
    nav a     { color: #fff; text-decoration: none; margin-right: 18px; font-size: 14px; }
    nav a:hover { text-decoration: underline; }
    .sig      { background: #003366; color: #fff; padding: 4px 10px; border-radius: 4px; font-family: monospace; display: inline-block; margin-bottom: 8px; }
  </style>
</head>
<body>

<nav>
  <a href="index.html">📋 README</a>
  <a href="01_config_variables.html">① Config</a>
  <a href="02_utility_functions.html">② Utilities</a>
  <a href="03_drive_configuration.html">③ Drive Config</a>
  <a href="04_ui_html_builder.html">④ HTML Builder</a>
  <a href="05_event_handlers.html">⑤ Event Handlers</a>
  <a href="06_machine_data.html">⑥ Machine Data</a>
</nav>

<h1>② Utility Functions</h1>
<p>
  These are the <strong>shared helper functions</strong> used throughout the whole script.
  They are called dozens (sometimes hundreds) of times during the configuration process.
  You don't need to change these unless there is a bug.
</p>

<!-- ===== CreateLogFile ===== -->
<h2>CreateLogFile</h2>
<div class="sig">Sub CreateLogFile</div>

<div class="explain">
  <strong>What it does:</strong><br>
  Creates a new script called <code>"LogFile"</code> inside the Starter project's Scripts section.
  If the log file already exists, it reuses it. Clears any old content.
  This is the start of the audit trail — every parameter value changed later is recorded here.
</div>

<pre class="code"><span class="keyword">Sub</span> CreateLogFile
    <span class="keyword">Dim</span> ConfigLogFile          <span class="comment">' This will hold a reference to the LogFile script object in Starter</span>
    <span class="keyword">Dim</span> ConfigLogFileText       <span class="comment">' (Reserved, not actually used in the body)</span>

    <span class="keyword">If</span> ConfigOption02_Logfile <span class="keyword">Then</span>   <span class="comment">' Only create the log if logging is enabled in config (see file 01)</span>
        On Error Resume Next            <span class="comment">' Don't crash if the script already exists — just handle it gracefully</span>

        Set ConfigLogFile = PROJ.Scripts.Item(ConfigLogFileName)  <span class="comment">' Try to get the existing "LogFile" script</span>

        <span class="keyword">If</span> (Err.Number&lt;&gt;0) <span class="keyword">Then</span>          <span class="comment">' If it didn't exist (error occurred)...</span>
            APP.PrintToLog <span class="string">"Log file Doesn't exist"</span>     <span class="comment">' ...log this fact to Starter's internal log</span>
            PROJ.Scripts.Add(ConfigLogFileName)              <span class="comment">' ...create a brand-new script named "LogFile"</span>
            APP.PrintToLog <span class="string">"Log file created"</span>
            Set ConfigLogFile = PROJ.Scripts.Item(ConfigLogFileName)  <span class="comment">' ...and get a reference to it</span>
        <span class="keyword">End If</span>

        <span class="comment">' Write a header line to the log so it's easy to see where one session starts</span>
        ConfigLogFile.Code=<span class="string">"' "</span>&amp;<span class="string">"-------------------- LogFile created -------------------"</span>&amp;vbCrLf
        <span class="comment">' vbCrLf = a newline character (carriage return + line feed)</span>
    <span class="keyword">End If</span>
<span class="keyword">End Sub</span>
</pre>

<!-- ===== PrintToLogFile ===== -->
<h2>PrintToLogFile</h2>
<div class="sig">Sub PrintToLogFile( logText )</div>

<div class="explain">
  <strong>What it does:</strong><br>
  Appends one line of text to the "LogFile" script in Starter.
  Called by <code>SetParam</code>, <code>SetSym</code>, and <code>PrintHeader</code>
  each time a parameter or symbol is changed.
  The logged text is prefixed with <code>'</code> so that the LogFile reads as valid VBScript comments.
</div>

<pre class="code"><span class="keyword">Sub</span> PrintToLogFile(logText)
    <span class="keyword">Dim</span> ConfigLogFile
    <span class="keyword">If</span> ConfigOption02_Logfile <span class="keyword">Then</span>     <span class="comment">' Only log if logging is enabled</span>
        Set ConfigLogFile = PROJ.Scripts.Item(ConfigLogFileName)    <span class="comment">' Get the LogFile script</span>
        ConfigLogFile.Code = ConfigLogFile.Code &amp; <span class="string">"'"</span> &amp; logText &amp; vbCrLf
        <span class="comment">' AppendS the new line: ConfigLogFile.Code is the existing content,
        ' plus "'" (makes it a VBScript comment), plus the new text, plus a newline</span>
    <span class="keyword">End If</span>
<span class="keyword">End Sub</span>
</pre>

<!-- ===== SetParam ===== -->
<h2>SetParam</h2>
<div class="sig">Sub SetParam( driveTO, parameter, index, newValue )</div>

<div class="explain">
  <strong>What it does:</strong><br>
  This is the <em>most important function</em> in the entire script.
  It writes a value to a Siemens drive parameter and records what changed in the log file.<br><br>
  <strong>Arguments:</strong>
  <ul>
    <li><code>driveTO</code> — the drive Technology Object (e.g., the Unwind drive object)</li>
    <li><code>parameter</code> — the Siemens parameter number (e.g., <code>210</code> = supply voltage)</li>
    <li><code>index</code> — the array index of that parameter (most parameters have [0], some have [1], [2] etc.)</li>
    <li><code>newValue</code> — the value to write (e.g., <code>400</code> for 400V)</li>
  </ul>
</div>

<pre class="code"><span class="keyword">Sub</span> SetParam(driveTO, parameter, index, newValue)
    oldValue = driveTO.Parameters(parameter, index)   <span class="comment">' Read the current value BEFORE changing it</span>
    driveTO.Parameters(parameter, index) = newValue   <span class="comment">' Write the new value to the drive</span>
    finalValue = driveTO.Parameters(parameter, index) <span class="comment">' Read back the value to verify it was accepted</span>
    <span class="comment">' NOTE: Sometimes drives reject a write if the value is out of range.
    '       finalValue lets us see what the drive actually stored.</span>

    <span class="comment">' ── Build the log line ──────────────────────────────────────────────────────────</span>
    <span class="comment">' Each column is padded to LogfilePadLength (15 chars) for aligned CSV output</span>
    DriveObjectName = Padding_Text(driveTo.Name, LogfilePadLength, <span class="string">" "</span>)  <span class="comment">' e.g. "Unwind         "</span>
    ParameterType   = Padding_Text(<span class="string">"Parameter"</span>,  LogfilePadLength, <span class="string">" "</span>)  <span class="comment">' always "Parameter      "</span>
    Parameter       = Padding_Text(parameter,   LogfilePadLength, <span class="string">" "</span>)  <span class="comment">' e.g. "210            "</span>
    index           = Padding_Text(index,        LogfilePadLength, <span class="string">" "</span>)  <span class="comment">' e.g. "0              "</span>
    OldValue        = Padding_Text(oldValue,     LogfilePadLength, <span class="string">" "</span>)
    NewValue        = Padding_Text(newValue,     LogfilePadLength, <span class="string">" "</span>)
    FinalValue      = Padding_Text(finalValue,   LogfilePadLength, <span class="string">" "</span>)

    <span class="keyword">If</span> ParameterEchoToScreen <span class="keyword">Then</span>  <span class="comment">' If debug echo is on, also print to HTML status bar</span>
        EchoToScreen(DriveObjectName &amp; <span class="string">","</span> &amp; ParameterType &amp; <span class="string">","</span> &amp; Parameter &amp; <span class="string">","</span> &amp; Index &amp; <span class="string">","</span> &amp; oldValue &amp; <span class="string">","</span> &amp; NewValue &amp; <span class="string">","</span> &amp; FinalValue)
    <span class="keyword">End If</span>

    PrintToLogFile(DriveObjectName &amp; <span class="string">","</span> &amp; ParameterType &amp; <span class="string">","</span> &amp; Parameter &amp; <span class="string">","</span> &amp; Index &amp; <span class="string">","</span> &amp; OldValue &amp; <span class="string">","</span> &amp; NewValue &amp; <span class="string">","</span> &amp; FinalValue)
    <span class="comment">' Log line example: "Unwind         ,Parameter      ,210            ,0              ,0              ,400            ,400            "</span>
<span class="keyword">End Sub</span>
</pre>

<!-- ===== Padding_Text ===== -->
<h2>Padding_Text</h2>
<div class="sig">Function Padding_Text( StringToPad, FinalStringLen, PadCharacter )</div>

<div class="explain">
  <strong>What it does:</strong><br>
  Takes a string and adds spaces (or any other character) to make it exactly
  <code>FinalStringLen</code> characters long. This makes the log file columns line up neatly.
  If <code>CompressedCSVLogfile = True</code>, it just returns the original string unchanged.
</div>

<pre class="code"><span class="keyword">Function</span> Padding_Text(StringToPad, FinalStringLen, PadCharacter)
    PaddingLength = FinalStringLen - Len(StringtoPad)  <span class="comment">' How many spaces do we need to add?</span>
    PaddedStringOut = StringToPad                       <span class="comment">' Start with the original string</span>

    <span class="keyword">For</span> i=1 <span class="keyword">To</span> PaddingLength                           <span class="comment">' Add spaces one at a time until correct length</span>
        PaddedStringOut = PaddedStringOut &amp; PadCharacter
    <span class="keyword">Next</span>

    <span class="keyword">If</span> CompressedCSVLogfile = <span class="keyword">True Then</span>
        Padding_Text = StringToPad       <span class="comment">' Compressed mode: return unpadded original</span>
    <span class="keyword">Else</span>
        Padding_Text = PaddedStringOut   <span class="comment">' Normal mode: return padded string</span>
    <span class="keyword">End If</span>
<span class="keyword">End Function</span>
</pre>

<!-- ===== SetSym ===== -->
<h2>SetSym</h2>
<div class="sig">Sub SetSym( driveTO, sym, newValue )</div>

<div class="explain">
  <strong>What it does:</strong><br>
  Similar to <code>SetParam</code>, but writes to a Siemens drive <em>Symbol</em>
  (a named alias for a parameter bit) instead of a raw parameter number.
  Symbols look like <code>p2100[0].1</code> — meaning parameter 2100, array index 0, bit 1.<br><br>
  The function also parses the symbol string to extract the parameter number and index
  so they can be logged in the same format as <code>SetParam</code>.
</div>

<pre class="code"><span class="keyword">Sub</span> SetSym(driveTO, sym, newValue)
    oldValue  = driveTO.Symbols(sym)    <span class="comment">' Read current symbol value</span>
    driveTO.Symbols(sym) = newValue     <span class="comment">' Write new value</span>
    finalValue = driveTO.Symbols(sym)   <span class="comment">' Read back to verify</span>

    <span class="comment">' ── Parse the symbol string to extract the parameter name and index ──────────</span>
    PeriodPosn = instr(sym, <span class="string">"."</span>)        <span class="comment">' Find position of the "." — e.g. "p2100[0].1" → period is at position 9</span>
    IndexText = mid(sym, PeriodPosn+1)  <span class="comment">' Everything after the period = bit index (e.g. "1")</span>

    IndexStartPosn = instr(sym, <span class="string">"["</span>)    <span class="comment">' Find position of "[" for array index</span>
    IndexEndPosn   = instr(sym, <span class="string">"]"</span>)    <span class="comment">' Find position of "]"</span>

    <span class="comment">' Extract the array digit(s) — could be single digit (0-9) or double digit (10-99)</span>
    <span class="keyword">If</span> IndexStartPosn &lt;&gt; 0 <span class="keyword">And</span> IndexEndPosn &lt;&gt; 0 <span class="keyword">Then</span>
        <span class="keyword">If</span> (IndexEndPosn - IndexStartPosn) = 2 <span class="keyword">Then</span>
            StringText1 = mid(sym, IndexStartPosn+1, 1)   <span class="comment">' Single digit: e.g. "[0]" → "0"</span>
        <span class="keyword">Else</span>
            StringText1 = mid(sym, IndexStartPosn+1, 2)   <span class="comment">' Double digit: e.g. "[10]" → "10"</span>
        <span class="keyword">End If</span>
    <span class="keyword">End If</span>

    <span class="comment">' Extract just the parameter number (strip the leading "p" character)</span>
    StringText = Left(sym, PeriodPosn-1)  <span class="comment">' e.g. "p2100[0]"</span>
    SymbolText = mid(StringText, 2)       <span class="comment">' Remove leading "p" → "2100[0]"</span>

    <span class="comment">' ── Build and log the output line ──────────────────────────────────────────────</span>
    SymbolType = Padding_Text(<span class="string">"Symbol"</span>, LogfilePadLength, <span class="string">" "</span>)
    <span class="comment">' ... (pad all values, then call PrintToLogFile — same pattern as SetParam)</span>
<span class="keyword">End Sub</span>
</pre>

<!-- ===== ConfirmWithUser ===== -->
<h2>ConfirmWithUser</h2>
<div class="sig">Function ConfirmWithUser( prompt )</div>

<div class="explain">
  <strong>What it does:</strong><br>
  Shows a Yes/No popup dialog to the engineer and returns <code>True</code> if they clicked Yes,
  <code>False</code> if they clicked No or pressed Cancel.
</div>

<pre class="code"><span class="keyword">Function</span> ConfirmWithUser(prompt)
    returnValue = MsgBox(prompt, 4, <span class="string">"Confirm:"</span>)
    <span class="comment">' MsgBox with parameter 4 = Yes/No buttons
    ' Return value 6 = Yes was clicked, anything else = No</span>
    ConfirmWithUser = (returnValue = 6)   <span class="comment">' Returns True only if Yes was clicked</span>
<span class="keyword">End Function</span>
</pre>

<!-- ===== GoOnline ===== -->
<h2>GoOnline</h2>
<div class="sig">Function GoOnline( TargetStateOnline )</div>

<div class="explain">
  <strong>What it does:</strong><br>
  Puts the Starter project <em>online</em> (connected to physical drives) or
  <em>offline</em> (disconnected). Returns <code>True</code> if the target state was achieved.<br><br>
  It always goes offline first before going online — this prevents communication conflicts.
</div>

<div class="warn">
  <strong>⚠️ Why go offline first?</strong>
  Siemens Starter can sometimes get "stuck" if you try to go online while already online.
  Going offline first resets the connection state cleanly.
</div>

<pre class="code"><span class="keyword">Function</span> GoOnline(TargertStateOnline)    <span class="comment">' Returns True if the requested state was reached</span>
    ThisProject.Online = <span class="keyword">False</span>          <span class="comment">' ALWAYS go offline first (resets connection state)</span>
    On Error Resume Next                  <span class="comment">' Don't crash if going online fails</span>

    <span class="keyword">If</span> TargertStateOnline <span class="keyword">Then</span>
        ThisProject.Online = <span class="keyword">True</span>        <span class="comment">' Try to go online (connect to real hardware)</span>
    <span class="keyword">Else</span>
        ThisProject.Online = <span class="keyword">False</span>       <span class="comment">' Explicitly stay offline</span>
    <span class="keyword">End If</span>

    GoOnline = ThisProject.Online         <span class="comment">' Return the actual current state
                                          ' (may be False even if True was requested, if connection failed)</span>
    On Error GoTo 0
<span class="keyword">End Function</span>
</pre>

<!-- ===== CheckExists ===== -->
<h2>CheckExists</h2>
<div class="sig">Function CheckExists( DeviceName, ThisName, ThisType, Alert )</div>

<div class="explain">
  <strong>What it does:</strong><br>
  Checks whether a given device, drive object, or sub-object exists in the Starter project.
  Returns <code>True</code> if found, <code>False</code> if not.
  Optionally shows an error popup if it's missing (<code>Alert = True</code>).
</div>

<table>
  <tr><th>ThisType</th><th>Checks for</th></tr>
  <tr><td>0</td><td>A Device (e.g., a CU320)</td></tr>
  <tr><td>1</td><td>A Technology Object inside a device (e.g., the Unwind drive)</td></tr>
  <tr><td>2</td><td>A SubObject inside a device (e.g., an infeed module)</td></tr>
</table>

<pre class="code"><span class="keyword">Function</span> CheckExists(DeviceName, ThisName, ThisType, Alert)
    On Error Resume Next
    <span class="keyword">If</span> ThisType=<span class="number">0</span> <span class="keyword">Then</span> Set ThisObject = PROJ.Devices(DeviceName)               <span class="comment">' Try to get device</span>
    <span class="keyword">If</span> ThisType=<span class="number">1</span> <span class="keyword">Then</span> Set ThisObject = PROJ.Devices(DeviceName).TOs(ThisName)   <span class="comment">' Try to get drive TO</span>
    <span class="keyword">If</span> ThisType=<span class="number">2</span> <span class="keyword">Then</span> Set ThisObject = PROJ.Devices(DeviceName).SubObjects(ThisName)

    <span class="keyword">If</span> Err.Number <span class="keyword">Then</span>           <span class="comment">' If any of the above failed (object not found)...</span>
        CheckExists = <span class="keyword">False</span>       <span class="comment">' ...return False</span>
        <span class="keyword">If</span> Alert ... <span class="keyword">Then</span> MsgBox(...)  <span class="comment">' ...and optionally show an error popup</span>
    <span class="keyword">Else</span>
        CheckExists = <span class="keyword">True</span>        <span class="comment">' Object was found OK</span>
    <span class="keyword">End If</span>
    On Error GoTo 0
<span class="keyword">End Function</span>
</pre>

<!-- ===== EchoToScreen / StatusLine ===== -->
<h2>EchoToScreen, StatusLine, StatusLineEcho</h2>

<div class="explain">
  <strong>What they do:</strong><br>
  These three functions update the HTML UI to show progress and status messages.
  <ul>
    <li><code>EchoToScreen(text)</code> — prints a message to the browser's status bar (bottom of window)</li>
    <li><code>StatusLine(lineNumber, colour, text)</code> — sets the text and colour of the status cell next to a step button (e.g., turns "Step 1" green with "Complete")</li>
    <li><code>StatusLineEcho</code> — calls both StatusLine and EchoToScreen at the same time</li>
  </ul>
</div>

<pre class="code"><span class="keyword">Sub</span> EchoToScreen(TextLine)
    APP.PrintToLog LineString    <span class="comment">' Print a divider line to Starter's internal log (for readability)</span>
    MainPage.StatusText = LineString
    APP.PrintToLog TextLine      <span class="comment">' Print the actual message</span>
    MainPage.StatusText = TextLine   <span class="comment">' Display in the browser window's status bar</span>
<span class="keyword">End Sub</span>

<span class="keyword">Sub</span> StatusLine(LineNumber, Colour, StatusText)
    <span class="comment">' Sets the text INSIDE the status cell next to button number LineNumber</span>
    <span class="comment">' e.g. StatusLine(1, "Green", "Complete") → step 1's status cell shows "Complete" in green</span>
    MainPage.Document.GetElementbyid(<span class="string">"out_"</span> &amp; CStr(LineNumber)).innerHTML = StatusText
    MainPage.Document.GetElementbyid(<span class="string">"out_"</span> &amp; CStr(LineNumber)).style.Color = Colour
<span class="keyword">End Sub</span>

<span class="keyword">Sub</span> StatusLineEcho(LineNumber, Colour, StatusText)
    MainPage.StatusText = StatusText    <span class="comment">' Update browser status bar</span>
    StatusLine LineNumber, Colour, StatusText  <span class="comment">' Also update the button's status cell</span>
<span class="keyword">End Sub</span>
</pre>

<hr>
<p style="color:#888; font-size:12px;">
  Continue to <a href="03_drive_configuration.html">③ Drive Configuration</a>.
</p>

</body>
</html>