File size: 36,024 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
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
<!DOCTYPE html>
<!--
================================================================================
  FILE: 06_machine_data.html
  PURPOSE: Documents the machine data management subroutines — the functions
           that load, save, display, and check the engineering data entered
           in the Machine Data form.

  FUNCTIONS COVERED:
    - CheckMachineDataExists  (line 2658) — called at startup; creates default data if none exists
    - LoadMachineData         (line 2836) — reads machine data from a saved script in Starter
    - DisplayMachineData      (line 2993) — copies loaded data into the HTML form fields
    - GetMachineData          (line 3141) — calls LoadMachineData + DisplayMachineData together
    - SaveMachineData         (line 3146) — reads the HTML form and saves to Starter script

  LINES IN ORIGINAL FILE: 2658 — 3300+

  WHERE IS MACHINE DATA STORED?
  Machine data is stored as a VBScript "Script" object inside the Starter project,
  with the name "MachineData". Its .Code property is a CSV-like text string
  containing all the values. See "Machine Data Text Format" below.
================================================================================
-->
<html>
<head>
  <meta charset="UTF-8">
  <title>06 — Machine Data | 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; margin-top: 20px; }
    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 #f7df1e; white-space: pre-wrap; }
    pre.data  { background: #0d1117; color: #a3d5ab; padding: 14px; border-radius: 6px;
                font-family: Consolas, monospace; font-size: 13px; overflow-x: auto;
                border-left: 4px solid #a3d5ab; 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; }
    table     { border-collapse: collapse; width: 100%; margin: 10px 0; }
    th        { background: #003366; color: white; padding: 8px; }
    td        { border: 1px solid #ccc; padding: 7px; vertical-align: top; }
    tr:nth-child(even) td { background: #f0f0f0; }
    .arrow    { color: #888; font-weight: bold; margin: 6px 0; display: block; }
  </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>⑥ Machine Data Management</h1>

<p>
  The "Machine Data" is the set of engineering values that describe the physical machine —
  roller diameters, gear ratios, motor types, encoder types, speed loop gains, etc.
  It must be entered once per machine by the commissioning engineer and is then stored
  inside the Starter project for reuse.
</p>

<!-- ===== WHERE IS MACHINE DATA STORED? ===== -->
<h2>Where Machine Data Is Stored</h2>

<div class="note">
  <strong>📌 Storage Location:</strong><br>
  Machine data is NOT stored as a regular file. It is stored as a <em>VBScript "Script" object</em>
  inside the Starter project (accessible via Project Navigator → Scripts → "MachineData").
  Its <code>.Code</code> property is a multi-line text string formatted as delimiter-separated values.
</div>

<h3>Machine Data Text Format</h3>
<p>
  The Delimit() function (see below) splits the text by <code>'</code> characters (row separator)
  and then by <code>,</code> characters (column separator).
</p>

<pre class="data"><span class="comment">' Row 1: Header comment (script version)</span>
' SINAMICS Script Machine Data S53b
<span class="comment">' Row 2: (reserved / not used)</span>
<span class="comment">' Row 3: Machine type, PLC type, machine name  (separated by commas)</span>
' 2,2,K5Expert_V24G001
<span class="comment">' Row 4: Supply voltage</span>
' 400
<span class="comment">' Row 5: Max line speed (m/min)</span>
' 1000
<span class="comment">' Row 6: Unwind layarm data (FW speed, FW speed enabled, max tension, max thrust)</span>
' 150,1,250.0,3000
<span class="comment">' Row 7: Rewind layarm data (same layout)</span>
' 150,1,250.0,3000
<span class="comment">' Rows 8 to 20: Per-drive data (one row per drive, drives 1-13)</span>
<span class="comment">' Format: GearRatio, Diameter, Speed, Torque, Direction, MotorType, Encoder, Gain, ResetTime, EnableConfig</span>
' 1.0,165,,, 1, -1, 1, 90, 50, 1     ← Drive 1 (Unwind)
' 1.0,194,,, 1, -1, 0, 27, 40, 1     ← Drive 2 (Draw)
' 2.857,700.0,,, 1, -1, 0, 40, 80, 1 ← Drive 3 (Drum)
...
<span class="comment">' Row 21: Winder drive type (0=unset, 1=Servo, 2=Vector)</span>
' 1
</pre>

<!-- ===== Delimit function ===== -->
<h2>Delimit() — CSV Parser</h2>
<div class="sig">Function Delimit( InputString, MatchNumber, Delimiter )</div>

<div class="explain">
  <strong>What it does:</strong><br>
  Splits a string by a delimiter character and returns the Nth piece.
  This is used to parse the machine data text format above.<br><br>
  Example: <code>Delimit("400,1,Test", 2, ",")</code> returns <code>"1"</code><br>
  Example: <code>Delimit("' 400" &amp; Chr(13) &amp; "' 480", 2, "'")</code> returns <code>" 480"</code>
</div>

<pre class="code"><span class="keyword">Function</span> Delimit(InputString, MatchNumber, Delimiter)
    DelimitCount=<span class="number">1</span>
    <span class="keyword">Dim</span> DelimitArray
    DelimitArray = Split(InputString, Delimiter)  <span class="comment">' Split the string into an array using the delimiter</span>
    Delimit = DelimitArray(MatchNumber-1)           <span class="comment">' Return the Nth element (1-based → 0-based)</span>
<span class="keyword">End Function</span>
<span class="comment">' Note: returns empty string if MatchNumber > number of elements</span>
</pre>

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

<div class="explain">
  <strong>When called:</strong> Once at startup, immediately after the HTML page is built.<br>
  <strong>What it does:</strong><br>
  Tries to load existing machine data. If no machine data exists yet (brand-new project),
  creates default values and saves them so subsequent loads work correctly.
</div>

<h3>Default Values Created on First Run</h3>

<table>
  <tr><th>Variable</th><th>Default Value</th><th>Meaning</th></tr>
  <tr><td><code>MachineData_Type</code></td><td>2</td><td>Machine uses timed E-stop (K5 Vision/Expert)</td></tr>
  <tr><td><code>MachineData_PlcType</code></td><td>2</td><td>TIA Portal PLC</td></tr>
  <tr><td><code>MachineData_Name</code></td><td>"None"</td><td>Machine name not set yet</td></tr>
  <tr><td><code>MachineData_SupplyVoltage</code></td><td>0</td><td>Not set — must be entered by engineer</td></tr>
  <tr><td><code>MachineData_LineSpeed</code></td><td>1000.0</td><td>Default 1000 m/min web speed</td></tr>
  <tr><td><code>MachineData_GearRatio(1-13)</code></td><td>Varies</td><td>Default gear ratios (1:1 for most, 2.857 for drums, blank for layarms)</td></tr>
  <tr><td><code>MachineData_Gain(1)</code> (Unwind)</td><td>90 (Servo) or 5 (Vector)</td><td>Speed loop proportional gain Kp</td></tr>
  <tr><td><code>MachineData_ResetTime(1)</code></td><td>50</td><td>Speed loop integral time Ti in ms</td></tr>
  <tr><td><code>MachineData_WinderDriveType</code></td><td>0</td><td>Not set — must be selected by engineer</td></tr>
</table>

<pre class="code"><span class="keyword">Sub</span> CheckMachineDataExists
    GetMachineData     <span class="comment">' Try to load existing data. Sets MachineDataExists=True or False.</span>
    <span class="keyword">If Not</span> MachineDataExists <span class="keyword">Then</span>   <span class="comment">' No saved data found — set sensible defaults</span>

        MachineData_Type=<span class="number">2</span>          <span class="comment">' Default: timed E-stop</span>
        MachineData_PlcType=<span class="number">2</span>       <span class="comment">' Default: TIA Portal</span>
        MachineData_Name=<span class="string">"None"</span>     <span class="comment">' No name yet</span>
        MachineData_SupplyVoltage=<span class="number">0</span> <span class="comment">' Not set</span>
        MachineData_Linespeed=<span class="number">1000.0</span>

        <span class="comment">' ── Line drives: Unwind(1), Draw(2), DTR2(5), Rewind(6), Draw2(9), Draw3(10), Draw4(13)</span>
        <span class="keyword">If</span> (index=<span class="number">1</span>) <span class="keyword">Or</span> (Index=<span class="number">2</span>) <span class="keyword">Or</span> (Index=<span class="number">5</span>) ... <span class="keyword">Then</span>
            MachineData_GearRatio(Index)=<span class="string">"1.0"</span>    <span class="comment">' 1:1 gear ratio</span>
            MachineData_RollDiameter(Index)=<span class="string">""</span>   <span class="comment">' Blank — must be filled by engineer</span>
            MachineData_Direction(Index)=<span class="number">0</span>        <span class="comment">' Not yet set</span>
        <span class="keyword">End If</span>

        <span class="comment">' ── Drums: Drum(3), Drum2(11), Drum3(12)</span>
        <span class="keyword">If</span> (Index=<span class="number">3</span>) <span class="keyword">Or</span> (Index=<span class="number">11</span>) <span class="keyword">Or</span> (Index=<span class="number">12</span>) <span class="keyword">Then</span>
            MachineData_GearRatio(Index)=<span class="string">"2.857"</span>  <span class="comment">' Drums always use 2.857:1 ratio</span>
        <span class="keyword">End If</span>

        <span class="comment">' ── Layarms / DTR1: DTR1(4), UnwindLayarm(7), RewindLayarm(8)</span>
        <span class="keyword">If</span> (Index=<span class="number">4</span>) <span class="keyword">Or</span> (Index=<span class="number">7</span>) <span class="keyword">Or</span> (Index=<span class="number">8</span>) <span class="keyword">Then</span>
            MachineData_GearRatio(Index)=<span class="string">""</span>    <span class="comment">' Will be read from drive schematic</span>
        <span class="keyword">End If</span>

        <span class="comment">' ── Default PID gains (changed based on drive type)</span>
        MachineData_Gain(<span class="number">1</span>)=<span class="number">90</span>  : MachineData_ResetTime(<span class="number">1</span>)=<span class="number">50</span>  <span class="comment">'Unwind Servo default</span>
        MachineData_Gain(<span class="number">2</span>)=<span class="number">27</span>  : MachineData_ResetTime(<span class="number">2</span>)=<span class="number">40</span>  <span class="comment">'Draw</span>
        MachineData_Gain(<span class="number">3</span>)=<span class="number">40</span>  : MachineData_ResetTime(<span class="number">3</span>)=<span class="number">80</span>  <span class="comment">'Drum</span>
        MachineData_Gain(<span class="number">4</span>)=<span class="number">15</span>  : MachineData_ResetTime(<span class="number">4</span>)=<span class="number">200</span> <span class="comment">'DTR1</span>
        MachineData_Gain(<span class="number">5</span>)=<span class="number">20</span>  : MachineData_ResetTime(<span class="number">5</span>)=<span class="number">200</span> <span class="comment">'DTR2</span>
        MachineData_Gain(<span class="number">7</span>)=<span class="number">0.8</span> : MachineData_ResetTime(<span class="number">7</span>)=<span class="number">15</span>  <span class="comment">'Unwind Layarm</span>
        MachineData_Gain(<span class="number">8</span>)=<span class="number">0.8</span> : MachineData_ResetTime(<span class="number">8</span>)=<span class="number">15</span>  <span class="comment">'Rewind Layarm</span>

        SaveMachineData    <span class="comment">' Write the defaults to the Starter script so they persist</span>
    <span class="keyword">End If</span>
<span class="keyword">End Sub</span>
</pre>

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

<div class="explain">
  <strong>What it does:</strong><br>
  Reads the "MachineData" script from the Starter project and parses the CSV-like text
  using the <code>Delimit()</code> function to fill all the <code>MachineData_*</code> array variables.
</div>

<span class="arrow">▼ Step 1: Try to access the "MachineData" script object in Starter</span>
<span class="arrow">▼ Step 2: If the script doesn't exist, set MachineDataExists = False and return</span>
<span class="arrow">▼ Step 3: If it does exist, read its .Code text and parse each row</span>

<pre class="code"><span class="keyword">Sub</span> LoadMachineData
    <span class="keyword">Dim</span> MachineDataScript   <span class="comment">' Will hold the Starter script object named "MachineData"</span>
    <span class="keyword">Dim</span> MDText               <span class="comment">' Will hold the text content of that script</span>
    On Error Resume Next
    Set MachineDataScript = PROJ.Scripts.Item(MachineDataScriptName)

    <span class="keyword">If</span> Err.Number&lt;&gt;0 <span class="keyword">Then</span>
        MachineDataExists=<span class="keyword">False</span>   <span class="comment">' Script doesn't exist = no data saved yet</span>
    <span class="keyword">Else</span>
        MachineDataExists=<span class="keyword">True</span>
    <span class="keyword">End If</span>

    <span class="keyword">If</span> MachineDataExists <span class="keyword">Then</span>
        MDText=MachineDataScript.Code   <span class="comment">' Read the entire text of the data script</span>

        <span class="comment">' ── Parse Row 3: Machine type, PLC type, name</span>
        MachineData_Type        = Delimit(Delimit(MDText,<span class="number">3</span>,<span class="string">"'"</span>),<span class="number">1</span>,<span class="string">","</span>)   <span class="comment">' Row 3, Column 1</span>
        MachineData_PlcType     = Delimit(Delimit(MDText,<span class="number">3</span>,<span class="string">"'"</span>),<span class="number">2</span>,<span class="string">","</span>)   <span class="comment">' Row 3, Column 2</span>
        MachineData_Name        = Delimit(Delimit(MDText,<span class="number">3</span>,<span class="string">"'"</span>),<span class="number">3</span>,<span class="string">","</span>)   <span class="comment">' Row 3, Column 3</span>

        <span class="comment">' ── Parse Row 4: Supply voltage</span>
        MachineData_SupplyVoltage = Int(Delimit(Delimit(MDText,<span class="number">4</span>,<span class="string">"'"</span>),<span class="number">1</span>,<span class="string">","</span>))

        <span class="comment">' ── Parse Row 5: Max line speed</span>
        MachineData_LineSpeed = Int(Delimit(<span class="string">"0"</span>&amp;Delimit(MDText,<span class="number">5</span>,<span class="string">"'"</span>),<span class="number">1</span>,<span class="string">","</span>))
        <span class="comment">' ↑ Note the "0" prepended — this prevents a crash if the row is blank (returns 0 instead of error)</span>

        <span class="comment">' ── Parse Rows 8 to 20: Per-drive data</span>
        <span class="keyword">For</span> index=1 <span class="keyword">To</span> NumDrives    <span class="comment">' Loop through all 13 drives</span>
            <span class="comment">' Row number = index + 7 (drives start at row 8, which is index 1 → row 1+7=8)</span>
            MachineData_GearRatio(Index)     = Delimit(Delimit(MDText,Index+<span class="number">7</span>,<span class="string">"'"</span>),<span class="number">1</span>,<span class="string">","</span>)
            MachineData_RollDiameter(Index)  = Delimit(Delimit(MDText,Index+<span class="number">7</span>,<span class="string">"'"</span>),<span class="number">2</span>,<span class="string">","</span>)
            MachineData_Speed(Index)         = Delimit(Delimit(MDText,Index+<span class="number">7</span>,<span class="string">"'"</span>),<span class="number">3</span>,<span class="string">","</span>)
            MachineData_Torque(Index)        = Delimit(Delimit(MDText,Index+<span class="number">7</span>,<span class="string">"'"</span>),<span class="number">4</span>,<span class="string">","</span>)
            MachineData_Direction(Index)     = Int(<span class="string">"0"</span>&amp;Delimit(Delimit(MDText,Index+<span class="number">7</span>,<span class="string">"'"</span>),<span class="number">5</span>,<span class="string">","</span>))
            MachineData_MotorType(Index)     = Int(Delimit(Delimit(MDText,Index+<span class="number">7</span>,<span class="string">"'"</span>),<span class="number">6</span>,<span class="string">","</span>))
            MachineData_Encoder(Index)       = Int(<span class="string">"0"</span>&amp;Delimit(Delimit(MDText,Index+<span class="number">7</span>,<span class="string">"'"</span>),<span class="number">7</span>,<span class="string">","</span>))
            MachineData_Gain(Index)          = Delimit(Delimit(MDText,Index+<span class="number">7</span>,<span class="string">"'"</span>),<span class="number">8</span>,<span class="string">","</span>)
            MachineData_ResetTime(Index)     = Delimit(Delimit(MDText,Index+<span class="number">7</span>,<span class="string">"'"</span>),<span class="number">9</span>,<span class="string">","</span>)
            MachineData_EnableConfig(Index)  = Delimit(Delimit(MDText,Index+<span class="number">7</span>,<span class="string">"'"</span>),<span class="number">10</span>,<span class="string">","</span>)
        <span class="keyword">Next</span>

        <span class="comment">' ── Parse Row 6: Unwind layarm data</span>
        MachineData_UnwindFWSpeed   = Delimit(Delimit(MDText,<span class="number">6</span>,<span class="string">"'"</span>),<span class="number">1</span>,<span class="string">","</span>)
        MachineData_UnwindFWSEnabled= Delimit(Delimit(MDText,<span class="number">6</span>,<span class="string">"'"</span>),<span class="number">2</span>,<span class="string">","</span>)
        MachineData_ULayarmMaxTension= Delimit(Delimit(MDText,<span class="number">6</span>,<span class="string">"'"</span>),<span class="number">3</span>,<span class="string">","</span>)
        MachineData_ULayarmMaxThrust = Delimit(Delimit(MDText,<span class="number">6</span>,<span class="string">"'"</span>),<span class="number">4</span>,<span class="string">","</span>)

        <span class="comment">' ── Parse Row 7: Rewind layarm data</span>
        MachineData_RewindFWSpeed    = Delimit(Delimit(MDText,<span class="number">7</span>,<span class="string">"'"</span>),<span class="number">1</span>,<span class="string">","</span>)
        MachineData_RewindFWSEnabled = Delimit(Delimit(MDText,<span class="number">7</span>,<span class="string">"'"</span>),<span class="number">2</span>,<span class="string">","</span>)
        MachineData_RLayarmMaxTension= Delimit(Delimit(MDText,<span class="number">7</span>,<span class="string">"'"</span>),<span class="number">3</span>,<span class="string">","</span>)
        MachineData_RLayarmMaxThrust = Delimit(Delimit(MDText,<span class="number">7</span>,<span class="string">"'"</span>),<span class="number">4</span>,<span class="string">","</span>)

        <span class="comment">' ── Parse Row 21: Winder drive type (added in S52a)</span>
        MachineData_WinderDriveType  = Delimit(Delimit(MDText,<span class="number">21</span>,<span class="string">"'"</span>),<span class="number">1</span>,<span class="string">","</span>)
    <span class="keyword">End If</span>
    On Error GoTo 0
<span class="keyword">End Sub</span>
</pre>

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

<div class="explain">
  <strong>What it does:</strong><br>
  Takes the values in the <code>MachineData_*</code> variables (filled by LoadMachineData)
  and pushes them into the HTML form fields so the engineer can see/edit them.
  Also:
  <ul>
    <li>Disables dropdowns that are forced by the config (e.g. if <code>ConfigMachineType=1</code>, the dropdown is greyed out)</li>
    <li>For each drive that exists in the project, overrides motor type and torque from the drive's DriveCliq data if available</li>
  </ul>
</div>

<pre class="code"><span class="keyword">Sub</span> DisplayMachineData
    <span class="keyword">If</span> MachineDataExists <span class="keyword">And</span> ShowMachineData <span class="keyword">Then</span>

        <span class="comment">' ── Apply forced machine settings ────────────────────────────────────────────
        '   If the config hard-codes the machine type, lock the dropdown</span>
        <span class="keyword">If</span> ConfigMachineType=<span class="number">1</span> <span class="keyword">Or</span> ConfigMachineType=<span class="number">2</span> <span class="keyword">Then</span>
            MachineData_Type=ConfigMachineType
            MainPage.Document.GetElementbyid(<span class="string">"MachineType"</span>).Disabled=<span class="keyword">True</span>   <span class="comment">' Grey out the dropdown</span>
        <span class="keyword">End If</span>

        <span class="comment">' ── Fill in header fields ────────────────────────────────────────────────────</span>
        MainPage.Document.GetElementbyid(<span class="string">"MachineName"</span>).Value        = MachineData_Name
        MainPage.Document.GetElementbyid(<span class="string">"MachineType"</span>).Value        = MachineData_Type
        MainPage.Document.GetElementbyid(<span class="string">"MachinePlcType"</span>).Value     = MachineData_PlcType
        MainPage.Document.GetElementbyid(<span class="string">"SupplyVoltage"</span>).Value      = MachineData_SupplyVoltage
        MainPage.Document.GetElementbyid(<span class="string">"WinderDriveType"</span>).Value    = MachineData_WinderDriveType
        MainPage.Document.GetElementbyid(<span class="string">"LineSpeed"</span>).Value          = MachineData_LineSpeed

        <span class="comment">' ── Fill in per-drive table ──────────────────────────────────────────────────</span>
        <span class="keyword">For</span> index=1 <span class="keyword">To</span> NumDrives
            MainPage.Document.GetElementbyid(<span class="string">"GearRatio_"</span>&amp;Index).Value  = MachineData_GearRatio(Index)
            MainPage.Document.GetElementbyid(<span class="string">"Diameter_"</span>&amp;Index).Value   = MachineData_RollDiameter(Index)
            MainPage.Document.GetElementbyid(<span class="string">"Speed_"</span>&amp;Index).Value      = MachineData_Speed(Index)
            MainPage.Document.GetElementbyid(<span class="string">"Direction_"</span>&amp;Index).Value  = MachineData_Direction(Index)
            MainPage.Document.GetElementbyid(<span class="string">"MotorType_"</span>&amp;Index).Value  = MachineData_MotorType(Index)
            MainPage.Document.GetElementbyid(<span class="string">"Torque_"</span>&amp;Index).Value     = MachineData_Torque(Index)
            MainPage.Document.GetElementbyid(<span class="string">"Encoder_"</span>&amp;Index).Value    = MachineData_Encoder(Index)
            MainPage.Document.GetElementbyid(<span class="string">"Gain_"</span>&amp;Index).Value       = MachineData_Gain(Index)
            MainPage.Document.GetElementbyid(<span class="string">"ResetTime_"</span>&amp;Index).Value  = MachineData_ResetTime(Index)
            MainPage.Document.GetElementbyid(<span class="string">"Enable_"</span>&amp;Index).Checked   = Not (MachineData_EnableConfig(Index)=0)

            <span class="comment">' ── Override motor type / torque from DriveCliq data if drive is in project ──</span>
            <span class="keyword">If</span> DrivePresent <span class="keyword">Then</span>
                <span class="keyword">If</span> DriveTo.Parameters(<span class="number">302</span>,<span class="number">0</span>)&gt;0 <span class="keyword">Then</span>    <span class="comment">' p302 > 0 = DriveCliq motor data identified</span>
                    MachineData_MotorType(Index)=-1      <span class="comment">' -1 = DriveCliq motor (auto-detected)</span>
                    MainPage.Document.GetElementbyid(<span class="string">"MotorType_"</span>&amp;Index).Value=-1
                    MainPage.Document.GetElementbyid(<span class="string">"Torque_"</span>&amp;Index).Value=DriveTo.Parameters(<span class="number">333</span>,<span class="number">0</span>)  <span class="comment">' p333 = rated torque from nameplate</span>
                    MainPage.Document.GetElementbyid(<span class="string">"MotorType_"</span>&amp;Index).Disabled=<span class="keyword">True</span>               <span class="comment">' Lock it</span>
                <span class="keyword">ElseIf</span> DriveTo.Parameters(<span class="number">302</span>,<span class="number">0</span>)=0 <span class="keyword">And</span> DriveTo.Parameters(<span class="number">304</span>,<span class="number">0</span>)&gt;0 <span class="keyword">Then</span>
                    MachineData_MotorType(Index)=-2      <span class="comment">' -2 = pre-configured (wizard), non-cliq</span>
                <span class="keyword">End If</span>
            <span class="keyword">End If</span>
        <span class="keyword">Next</span>

        <span class="comment">' ── Fill in layarm fields ────────────────────────────────────────────────────</span>
        MainPage.Document.GetElementbyid(<span class="string">"MaxSpeed_1"</span>).Value              = MachineData_UnwindFWSpeed
        MainPage.Document.GetElementbyid(<span class="string">"MaxSpeedEnable_1"</span>).Checked       = (MachineData_UnwindFWSEnabled=1)
        MainPage.Document.GetElementbyid(<span class="string">"UnwLayarmMaxTensSetpoint"</span>).Value  = MachineData_ULayarmMaxTension
        MainPage.Document.GetElementbyid(<span class="string">"UnwLayarmMaxThrust"</span>).Value        = MachineData_ULayarmMaxThrust
        MainPage.Document.GetElementbyid(<span class="string">"MaxSpeed_6"</span>).Value              = MachineData_RewindFWSpeed
        MainPage.Document.GetElementbyid(<span class="string">"MaxSpeedEnable_6"</span>).Checked       = (MachineData_RewindFWSEnabled=1)
        MainPage.Document.GetElementbyid(<span class="string">"RewLayarmMaxTensSetpoint"</span>).Value  = MachineData_RLayarmMaxTension
        MainPage.Document.GetElementbyid(<span class="string">"RewLayarmMaxThrust"</span>).Value        = MachineData_RLayarmMaxThrust

        Call MainPage.Document.GetElementbyid(<span class="string">"RewLayarmMaxThrust"</span>).onblur   <span class="comment">' Trigger the onblur event to fire the JS update() function</span>
    <span class="keyword">End If</span>
<span class="keyword">End Sub</span>
</pre>

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

<div class="explain">
  <strong>What it does:</strong><br>
  The reverse of LoadMachineData. Reads the current HTML form values (if the Machine Data
  form is visible) into the <code>MachineData_*</code> arrays, then rebuilds the CSV text
  and writes it back to the "MachineData" script object in Starter.
</div>

<pre class="code"><span class="keyword">Sub</span> SaveMachineData
    <span class="keyword">Dim</span> MachineDataScript
    On Error Resume Next
    Set MachineDataScript = PROJ.Scripts.Item(MachineDataScriptName)

    <span class="keyword">If</span> Err.Number&lt;&gt;0 <span class="keyword">Then</span>   <span class="comment">' Script doesn't exist yet — create it</span>
        PROJ.Scripts.Add(MachineDataScriptName)
        Set MachineDataScript = PROJ.Scripts.Item(MachineDataScriptName)
    <span class="keyword">End If</span>

    <span class="keyword">If</span> ShowMachineData <span class="keyword">Then</span>   <span class="comment">' Only read from the screen if the form is currently visible</span>
        MachineData_Name         = MainPage.Document.GetElementbyid(<span class="string">"MachineName"</span>).Value
        MachineData_Type         = MainPage.Document.GetElementbyid(<span class="string">"MachineType"</span>).Value
        MachineData_PlcType      = MainPage.Document.GetElementbyid(<span class="string">"MachinePlcType"</span>).Value
        MachineData_SupplyVoltage= MainPage.Document.GetElementbyid(<span class="string">"SupplyVoltage"</span>).Value
        MachineData_LineSpeed    = MainPage.Document.GetElementbyid(<span class="string">"LineSpeed"</span>).Value
        <span class="comment">'... (read all 10 fields for each of the 13 drives)</span>
    <span class="keyword">End If</span>

    <span class="comment">' ── Build the CSV text and write it ──────────────────────────────────────────
    '   Each .Code = ... line appends another row to the script text'</span>
    MachineDataScript.Code  = <span class="string">"' SINAMICS Script Machine Data "</span> &amp; ConfigVersion &amp; vbCrLf
    MachineDataScript.Code = MachineDataScript.Code &amp; <span class="string">"' "</span> &amp; vbCrLf                          <span class="comment">' Row 2 (blank)</span>
    MachineDataScript.Code = MachineDataScript.Code &amp; <span class="string">"' "</span> &amp; MachineData_Type &amp; <span class="string">","</span> &amp; MachineData_PlcType &amp; <span class="string">","</span> &amp; MachineData_Name &amp; vbCrLf  <span class="comment">' Row 3</span>
    MachineDataScript.Code = MachineDataScript.Code &amp; <span class="string">"' "</span> &amp; MachineData_SupplyVoltage &amp; vbCrLf  <span class="comment">' Row 4</span>
    MachineDataScript.Code = MachineDataScript.Code &amp; <span class="string">"' "</span> &amp; MachineData_LineSpeed &amp; vbCrLf       <span class="comment">' Row 5</span>
    <span class="comment">' Row 6: Unwind layarm</span>
    MachineDataScript.Code = MachineDataScript.Code &amp; <span class="string">"' "</span> &amp; MachineData_UnwindFWSpeed &amp; <span class="string">","</span> &amp; MachineData_UnwindFWSEnabled &amp; <span class="string">","</span> &amp; MachineData_ULayarmMaxTension &amp; <span class="string">","</span> &amp; MachineData_ULayarmMaxThrust &amp; vbCrLf
    <span class="comment">' Row 7: Rewind layarm</span>
    MachineDataScript.Code = MachineDataScript.Code &amp; <span class="string">"' "</span> &amp; MachineData_RewindFWSpeed &amp; <span class="string">","</span> &amp; MachineData_RewindFWSEnabled &amp; <span class="string">","</span> &amp; MachineData_RLayarmMaxTension &amp; <span class="string">","</span> &amp; MachineData_RLayarmMaxThrust &amp; vbCrLf
    <span class="comment">' Rows 8-20: Per-drive data</span>
    <span class="keyword">For</span> index=1 <span class="keyword">To</span> NumDrives
        MachineDataScript.Code = MachineDataScript.Code &amp; <span class="string">"' "</span> &amp; _
            MachineData_GearRatio(index) &amp; <span class="string">","</span> &amp; MachineData_RollDiameter(index) &amp; <span class="string">","</span> &amp; _
            MachineData_Speed(index) &amp; <span class="string">","</span> &amp; MachineData_Torque(index) &amp; <span class="string">","</span> &amp; _
            MachineData_Direction(index) &amp; <span class="string">","</span> &amp; MachineData_MotorType(index) &amp; <span class="string">","</span> &amp; _
            MachineData_Encoder(index) &amp; <span class="string">","</span> &amp; MachineData_Gain(index) &amp; <span class="string">","</span> &amp; _
            MachineData_ResetTime(index) &amp; <span class="string">","</span> &amp; MachineData_EnableConfig(index) &amp; vbCrLf
    <span class="keyword">Next</span>
    <span class="comment">' ... (winder type goes to row 21)</span>
<span class="keyword">End Sub</span>
</pre>

<h3>Complete Machine Data Variable Reference</h3>

<table>
  <tr><th>Variable Name</th><th>HTML Form ID</th><th>Siemens Parameter Written</th></tr>
  <tr><td><code>MachineData_Name</code></td><td>MachineName</td><td>Not written to drives (display only)</td></tr>
  <tr><td><code>MachineData_Type</code></td><td>MachineType</td><td>p2126[2] on CU (machine E-stop type)</td></tr>
  <tr><td><code>MachineData_PlcType</code></td><td>MachinePlcType</td><td>p2126[3] on CU (PLC speed word width)</td></tr>
  <tr><td><code>MachineData_SupplyVoltage</code></td><td>SupplyVoltage</td><td>p210 on each infeed and drive</td></tr>
  <tr><td><code>MachineData_LineSpeed</code></td><td>LineSpeed</td><td>Used to calculate p2000 (reference speed) for each drive</td></tr>
  <tr><td><code>MachineData_GearRatio(n)</code></td><td>GearRatio_n</td><td>Used to calculate p2000 and p1082</td></tr>
  <tr><td><code>MachineData_RollDiameter(n)</code></td><td>Diameter_n</td><td>Used to calculate p2000 and p1082 (mm)</td></tr>
  <tr><td><code>MachineData_Speed(n)</code></td><td>Speed_n (read-only, calculated)</td><td>p2000[0] = reference speed AND p1082 = max speed</td></tr>
  <tr><td><code>MachineData_Direction(n)</code></td><td>Direction_n</td><td>p1821 (CW=0, CCW=1)</td></tr>
  <tr><td><code>MachineData_MotorType(n)</code></td><td>MotorType_n</td><td>Determines which parameters to write for motor characterization</td></tr>
  <tr><td><code>MachineData_Encoder(n)</code></td><td>Encoder_n</td><td>Determines encoder type settings (p400 series)</td></tr>
  <tr><td><code>MachineData_Torque(n)</code></td><td>Torque_n</td><td>p2003 (reference torque in Nm)</td></tr>
  <tr><td><code>MachineData_Gain(n)</code></td><td>Gain_n</td><td>p1460[0] (speed loop proportional gain Kp)</td></tr>
  <tr><td><code>MachineData_ResetTime(n)</code></td><td>ResetTime_n</td><td>p1462[0] (speed loop integral time Ti in ms)</td></tr>
  <tr><td><code>MachineData_EnableConfig(n)</code></td><td>Enable_n (checkbox)</td><td>If 0, skip configuring this drive entirely</td></tr>
  <tr><td><code>MachineData_WinderDriveType</code></td><td>WinderDriveType</td><td>1=Servo → Kp=90, Ti=50ms; 2=Vector → Kp=5, Ti=50ms</td></tr>
  <tr><td><code>MachineData_ULayarmMaxThrust</code></td><td>UnwLayarmMaxThrust</td><td>p2126[14] on CU (max layarm force in Newtons)</td></tr>
</table>

<hr>
<p style="color:#888; font-size:12px;">
  ← You have reached the end of the documentation. Return to <a href="index.html">README</a>.
</p>

</body>
</html>