Daqfactory Usersguide
Daqfactory Usersguide
DAQFactory for Windows, Version 5.86, Tuesday, September 20, 2011: Copyright 2001-2011 AzeoTech, Inc. All rights reserved worldwide. Information in this document is subject to change without notice. AzeoTech is a registered trademark of AzeoTech, Inc. DAQFactory is a registered trademark of AzeoTech, Inc. Other brand and product names are trademarks of their respective holders.
This manual: Copyright 2011 AzeoTech, Inc. All rights reserved worldwide. No portion of this manual may be copied, modified, translated, or reduced into machine-readable form without the prior written consent of AzeoTech, Inc.
Contents
Table of Contents
1 Introducing DAQFactory 15
1.1 End User License Agreement ................................................................................................................................... 15 1.2 Acknowledgements ................................................................................................................................... 18 1.3 Welcome to DAQFactory ................................................................................................................................... 19 1.4 System Requirements ................................................................................................................................... 19 1.5 DAQFactory Performance ................................................................................................................................... 20 1.6 Licensing DAQFactory ................................................................................................................................... 21 1.7 Moving a license ................................................................................................................................... 22 1.8 Using the hardware key option ................................................................................................................................... 23 1.9 Upgrading to a................................................................................................................................... 23 different version of DAQFactory 1.10 For users of earlier versions of DAQFactory ................................................................................................................................... 24 1.11 DAQFactory's User Interface ................................................................................................................................... 25 1.12 DAQFactory Objects ................................................................................................................................... 27
2 Guided Tour
32
2.1 Tour Overview................................................................................................................................... 32 2.2 Tour Assumptions ................................................................................................................................... 32 2.3 Tour Terminology ................................................................................................................................... 32 2.4 Starting DAQFactory ................................................................................................................................... 32 2.5 Creating Channels ................................................................................................................................... 32 2.6 Displaying the ................................................................................................................................... 35 Data 2.7 Graphing the data ................................................................................................................................... 39 2.8 Controlling an ................................................................................................................................... 44 output 2.9 Logging Data ................................................................................................................................... 46 2.10 Viewing Data ................................................................................................................................... 48 on the Web
53
3.1 Document Overview ................................................................................................................................... 53 3.2 Starting a new ................................................................................................................................... 53 document 3.3 Saving a document ................................................................................................................................... 53 3.4 Saving with History ................................................................................................................................... 53 3.5 Opening a document ................................................................................................................................... 54 3.6 Safe mode ................................................................................................................................... 54 3.7 Autoloading a document ................................................................................................................................... 55 3.8 Document settings ................................................................................................................................... 55
4 Expressions
59
4.1 Expressions Overview ................................................................................................................................... 59 4.2 Using expressions ................................................................................................................................... 59 4.3 The command ................................................................................................................................... 59 line interface 4.4 The big expression window ................................................................................................................................... 60 4.5 Arrays 4.6 Subsetting 4.7 Strings ................................................................................................................................... 61 ................................................................................................................................... 62 ................................................................................................................................... 63
4.8 Entering hex and binary constants ................................................................................................................................... 63 4.9 Entering in constant time values ................................................................................................................................... 64 4.10 Object variables and functions ................................................................................................................................... 64 4.11 Specifying Connections in Expressions ................................................................................................................................... 65 4.12 Expression Operator / Function Reference ................................................................................................................................... 65
4.12.1 Order of operations .......................................................................................................................................................... 4.12.2 Boolean operators .......................................................................................................................................................... 4.12.3 Math operators .......................................................................................................................................................... 4.12.4 Bitwise operators and functions .......................................................................................................................................................... 4.12.5 Math functions.......................................................................................................................................................... 4.12.6 Trigometric functions .......................................................................................................................................................... 4.12.7 Statistical functions .......................................................................................................................................................... 4.12.8 Boxcar averaging and smoothing functions .......................................................................................................................................................... 4.12.9 String functions .......................................................................................................................................................... 4.12.10 Byte conversions .......................................................................................................................................................... 4.12.11 Time functions .......................................................................................................................................................... 4.12.12 Array creation and manipulation functions .......................................................................................................................................................... 4.12.13 Random Number functions .......................................................................................................................................................... 4.12.14 Thermocouple conversion functions .......................................................................................................................................................... 4.12.15 Misc functions .......................................................................................................................................................... 4.12.16 Constants .......................................................................................................................................................... 4.12.17 Advanced Analysis functions .......................................................................................................................................................... 65 66 66 67 68 69 70 71 72 78 82 85 86 87 87 87 89
98
5.1 Sequence Overview ................................................................................................................................... 98 5.2 Creating a New Sequence ................................................................................................................................... 98 5.3 Starting and Stopping a Sequence ................................................................................................................................... 100 5.4 The most basic sequence and assignment ................................................................................................................................... 100 5.5 More advanced assignment operators and the arraystep statement ................................................................................................................................... 100 5.6 Reading inputs with the read statement and process control loops ................................................................................................................................... 101
2011 AzeoTech, Inc.
Contents
5.7 Programmatically starting and stopping things ................................................................................................................................... 103 5.8 Timed sequences and the goto statement ................................................................................................................................... 104 5.9 Waiting in a sequence ................................................................................................................................... 105 5.10 Variables ................................................................................................................................... 108 5.11 Private sequence variables ................................................................................................................................... 112 5.12 Conditional branching with the if statement ................................................................................................................................... 113 5.13 Replacing multiple ifs with a switch statement ................................................................................................................................... 114 5.14 Sequence looping with the while statement ................................................................................................................................... 115 5.15 Looping while counting with the for statement ................................................................................................................................... 115 5.16 Avoiding being hanged using the infinite loop check ................................................................................................................................... 116 5.17 Using sequences as functions ................................................................................................................................... 117 5.18 Running commands in a string with the execute function ................................................................................................................................... 118 5.19 Error handling with try/catch ................................................................................................................................... 119 5.21 Sequence Threads and Thread Priority ................................................................................................................................... 121 5.22 Auto-Start ................................................................................................................................... 122 5.23 Sequence debugging ................................................................................................................................... 122 5.24 Printing to the Command / Alert window ................................................................................................................................... 122 5.25 Watch window ................................................................................................................................... 123 5.26 Sequence Functions ................................................................................................................................... 123 5.27 System Functions ................................................................................................................................... 124 5.28 System Events ................................................................................................................................... 127 5.29 Questions, Answers and Examples ................................................................................................................................... 129
5.29.1 Misc sequence comments .......................................................................................................................................................... 5.29.2 Array manipulation .......................................................................................................................................................... 5.29.3 Start a sequence on the second .......................................................................................................................................................... 129 130 132
134
6.1 Channel and Conversion Overview ................................................................................................................................... 134 6.2 Channels and................................................................................................................................... 134 the Channel Table 6.3 Channel Import and Export ................................................................................................................................... 137 6.4 Channel History and Persistence ................................................................................................................................... 137 6.5 Channel Groups ................................................................................................................................... 139 6.6 Device Configurator ................................................................................................................................... 140 6.7 The Channel View ................................................................................................................................... 140 6.8 Fine Tuning Data Acquisition ................................................................................................................................... 140 6.9 Channel Functions and Variables ................................................................................................................................... 143 6.10 Channel List................................................................................................................................... 145 Functions 6.11 Conversions and the Conversion Table ................................................................................................................................... 146 6.12 V Channels ................................................................................................................................... 147 6.13 Questions, Answers and Examples ................................................................................................................................... 148
6.13.1 Oversampling a channel (averaging) .......................................................................................................................................................... 2011 AzeoTech, Inc. 148
151
7.1 Page and Component Overview ................................................................................................................................... 151 7.2 Adding Components to Pages ................................................................................................................................... 151 7.3 Arranging Components on the Page ................................................................................................................................... 151 7.4 Edit mode ................................................................................................................................... 152 7.5 Grouping Components ................................................................................................................................... 153 7.6 Creating User................................................................................................................................... 153 Components 7.7 Using the Grid and Movement Lock ................................................................................................................................... 154 7.8 Component Find and Replace ................................................................................................................................... 154 7.9 Multiple Pages and Page Properties ................................................................................................................................... 154 7.10 Creating Popups ................................................................................................................................... 155 7.11 Full screen mode ................................................................................................................................... 156 7.12 Creating multi-lingual applications ................................................................................................................................... 157 7.13 Printing Pages ................................................................................................................................... 159 7.14 Page Functions ................................................................................................................................... 159 7.15 Component Names ................................................................................................................................... 161 7.16 Component Properties and Events ................................................................................................................................... 162 7.17 Component Actions ................................................................................................................................... 164 7.18 The Components ................................................................................................................................... 165
7.18.1 Static .......................................................................................................................................................... 7.18.1.1 Text Component ......................................................................................................................................................... 7.18.1.2 Panel Component ......................................................................................................................................................... 7.18.2 Displays .......................................................................................................................................................... 7.18.2.1 Variable Value Component ......................................................................................................................................................... 7.18.2.2 Descriptive Text Component ......................................................................................................................................................... 7.18.2.3 Symbol Component ......................................................................................................................................................... 7.18.2.4 The Color Property Page ......................................................................................................................................................... 7.18.2.5 The Size Property Page ......................................................................................................................................................... 7.18.2.6 Table Component ......................................................................................................................................................... 7.18.2.7 Canvas Component ......................................................................................................................................................... 7.18.2.8 LED Components ......................................................................................................................................................... 7.18.2.9 Progress Bar Component ......................................................................................................................................................... 7.18.3 Gauges .......................................................................................................................................................... 7.18.3.1 Linear ......................................................................................................................................................... Gauge and Log Gauge Component 7.18.3.2 Angular Gauge and Angular Log Gauge Component ......................................................................................................................................................... 7.18.3.3 LED Bar Gauge Component ......................................................................................................................................................... 7.18.4 Compasses .......................................................................................................................................................... 7.18.4.1 Compass Component ......................................................................................................................................................... 7.18.4.2 Dual Compass Component ......................................................................................................................................................... 7.18.5 Percent .......................................................................................................................................................... 7.18.5.1 Percent Bar and Pie Chart Component ......................................................................................................................................................... 7.18.6 Graphs .......................................................................................................................................................... 7.18.6.1 2D Graph Component ......................................................................................................................................................... 165 165 166 166 166 167 168 170 171 172 173 177 177 177 177 179 182 183 183 184 185 185 187 187
Contents
7
187 188 188 189 189 189 190 190 191 191 192 192 193 193 193 195 196 196 197 197 197 200 202
7.18.6.2 3D Graph Component ......................................................................................................................................................... 7.18.6.3 Image ......................................................................................................................................................... Component 7.18.6.4 Spectrum Display Component ......................................................................................................................................................... 7.18.7 Buttons_&_Switches .......................................................................................................................................................... 7.18.7.1 Button......................................................................................................................................................... Component 7.18.7.2 Check ......................................................................................................................................................... Box Component 7.18.7.3 Spin Button Component ......................................................................................................................................................... 7.18.7.4 Lever Switch Component ......................................................................................................................................................... 7.18.7.5 Rocker Switch Component ......................................................................................................................................................... 7.18.7.6 Toggle......................................................................................................................................................... Switch Component 7.18.7.7 Valve Component ......................................................................................................................................................... 7.18.7.8 Three ......................................................................................................................................................... Way Rocker Component 7.18.7.9 Four Way Switch Component ......................................................................................................................................................... 7.18.8 Edit_Controls.......................................................................................................................................................... 7.18.8.1 Edit Box, Password Edit, and Multiline Edit Box Component ......................................................................................................................................................... 7.18.8.2 Date & Time Edit Component ......................................................................................................................................................... 7.18.9 Selection .......................................................................................................................................................... 7.18.9.1 Combo Box and Radio Buttons Components ......................................................................................................................................................... 7.18.9.2 Tree List Component ......................................................................................................................................................... 7.18.10 Sliders_&_Knobs .......................................................................................................................................................... 7.18.10.1 Knob......................................................................................................................................................... Component 7.18.10.2 Slider Component ......................................................................................................................................................... 7.18.10.3 Scroll......................................................................................................................................................... Bar Component
210
8.1 Graph Overview ................................................................................................................................... 210 8.2 Creating a Value vs Time (Trend) graph ................................................................................................................................... 210 8.3 Graph scaling, zooming, and panning ................................................................................................................................... 211 8.4 Adding more ................................................................................................................................... 212 traces to the graph 8.5 Multiple Axes................................................................................................................................... 212 8.6 Colorizing Traces ................................................................................................................................... 213 8.7 Error Bars ................................................................................................................................... 213 8.8 Wind barbs ................................................................................................................................... 214 8.9 Axis and Line................................................................................................................................... 214 annotations 8.10 Other graph ................................................................................................................................... 215 properties 8.11 X vs Y graphs ................................................................................................................................... 216 8.12 Advanced graphing ................................................................................................................................... 217 8.13 Graph variables and functions ................................................................................................................................... 218
222
9.1 Data Logging................................................................................................................................... 222 Overview 9.2 Creating a logging set ................................................................................................................................... 222
DAQFactory User's Guide 9.3 Logging Notes and Alerts ................................................................................................................................... 224 9.4 ODBC Database logging ................................................................................................................................... 225 9.5 Reading from................................................................................................................................... 227 an ODBC Database 9.6 Binary logging ................................................................................................................................... 229 9.7 Export Sets ................................................................................................................................... 229 9.8 Logging / Export Set Functions ................................................................................................................................... 230 9.9 Direct file access ................................................................................................................................... 232 9.10 Questions, Answers and Examples ................................................................................................................................... 235
9.10.1 Write data to a file from a sequence .......................................................................................................................................................... 9.10.2 Read a file and set an output channel from its data .......................................................................................................................................................... 9.10.3 DAQFactory / .......................................................................................................................................................... Excel Time 9.10.4 Logging on an event .......................................................................................................................................................... 9.10.5 Changing the .......................................................................................................................................................... logging file name every month 9.10.6 Changing the .......................................................................................................................................................... logging file name every day 235 237 239 239 239 240
10 PID Loops
243
10.1 PID Overview ................................................................................................................................... 243 10.2 Creating a new PID loop ................................................................................................................................... 243 10.3 Autotuning ................................................................................................................................... 245 10.4 PID Event ................................................................................................................................... 245 10.5 PID Variables and Functions ................................................................................................................................... 246 10.6 Questions, Answers and Examples ................................................................................................................................... 247
10.6.1 PID Algorithm? .......................................................................................................................................................... 247
11 Alarming
249
11.1 Alarming Overview ................................................................................................................................... 249 11.2 Creating a new alarm ................................................................................................................................... 249 11.3 Alarm Summary View ................................................................................................................................... 250 11.4 Alarm Logging ................................................................................................................................... 250 11.5 Alarm Variables and Functions ................................................................................................................................... 251 11.6 Questions, Answers and Examples ................................................................................................................................... 253
11.6.1 Basic Alarming .......................................................................................................................................................... 253
12 Networking / Connectivity
257
12.1 Networking overview ................................................................................................................................... 257 12.2 Real time Web with DAQConnect ................................................................................................................................... 257 12.3 Email - SMTP outgoing ................................................................................................................................... 259 12.4 Email - POP3 incoming ................................................................................................................................... 260 12.5 FTP ................................................................................................................................... 262 12.6 Voice Modem / AutoDialer (TAPI) ................................................................................................................................... 262 12.7 Connecting to a remote copy of DAQFactory ................................................................................................................................... 265 12.8 Internal Web................................................................................................................................... 267 Server (deprecated)
Contents
12.10 Using DDE ................................................................................................................................... 267 to transfer data to other windows applications
13 Analysis
270
13.1 Analysis overview ................................................................................................................................... 270 13.2 Analysis Tools ................................................................................................................................... 270 13.3 Capturing Channels and Graphs ................................................................................................................................... 270 13.4 General Statistics ................................................................................................................................... 271 13.5 Curve Fitting ................................................................................................................................... 271 13.6 Correlation and convolution ................................................................................................................................... 272 13.7 Histogram ................................................................................................................................... 272 13.8 Interpolation ................................................................................................................................... 273 13.9 Percentile 13.10 FFT ................................................................................................................................... 273 ................................................................................................................................... 273
14 Other Features
276
14.1 Startup Flags ................................................................................................................................... 276 14.2 Preferences ................................................................................................................................... 276 14.3 Alerts ................................................................................................................................... 277 14.4 Quick Notes................................................................................................................................... 277 14.5 Customizing................................................................................................................................... 278 14.6 DAQFactory ................................................................................................................................... 278 Runtime 14.7 Acquire mode ................................................................................................................................... 280 14.8 User defined time reference ................................................................................................................................... 281
15 Extending DAQFactory
283
283 283 284 285
289
16.1 DAQFactory................................................................................................................................... 289 Communications Overview 16.2 Creating a Comm Device ................................................................................................................................... 289 16.3 The Comm Protocol ................................................................................................................................... 290 16.4 Using Comm Devices ................................................................................................................................... 291 16.5 Monitoring and Debugging Communications ................................................................................................................................... 292 16.6 Low Level Comm ................................................................................................................................... 293
10
DAQFactory User's Guide 16.7 Low Level Comm Syncronization ................................................................................................................................... 294 16.8 User Comm ................................................................................................................................... 295 Protocols 16.9 Predefined Protocols ................................................................................................................................... 296
16.9.1 Allen Bradley .......................................................................................................................................................... DF1 protocol 16.9.2 DataForth isoLynx protocol .......................................................................................................................................................... 16.9.3 Mitsubishi A/Q protocol .......................................................................................................................................................... 16.9.4 Mitsubishi FX.......................................................................................................................................................... direct serial protocol 16.9.5 ModbusTCP/RTU/ASCII Master protocols .......................................................................................................................................................... 16.9.6 ModbusTCP/RTU/ASCII Slave protocol .......................................................................................................................................................... 296 303 304 305 307 310
17 Devices
312
17.1 Device Overview ................................................................................................................................... 312 17.2 Device Functions ................................................................................................................................... 312 17.3 Acces I/O Device ................................................................................................................................... 312 17.4 Diamond Systems device ................................................................................................................................... 316 17.5 DDE Client device ................................................................................................................................... 320 17.6 ICP-DAS i7000 ................................................................................................................................... 320 17.7 LabJack UE9 / U6 / U3 ................................................................................................................................... 322 17.8 LabJack U12 device ................................................................................................................................... 324 17.9 Measurement Computing / Computerboards device ................................................................................................................................... 329 17.10 National Instruments NI435x device ................................................................................................................................... 330 17.11 National Instruments NIDAQ device ................................................................................................................................... 331 17.12 OPC device ................................................................................................................................... 331 17.13 RFScada device ................................................................................................................................... 333 17.14 Sensoray SmartAD device ................................................................................................................................... 335 17.15 Test device................................................................................................................................... 336 17.16 TriLogi device ................................................................................................................................... 337
340
................................................................................................................................... 340 ................................................................................................................................... 340 ................................................................................................................................... 340 ................................................................................................................................... 340 ................................................................................................................................... 340 ................................................................................................................................... 340 ................................................................................................................................... 341 ................................................................................................................................... 341 ................................................................................................................................... 341 ................................................................................................................................... 341 ................................................................................................................................... 341 ................................................................................................................................... 341 ................................................................................................................................... 341
2011 AzeoTech, Inc.
Contents C1013 C1014 C1015 C1016 C1017 C1018 C1019 C1020 C1021 C1022 C1023 C1024 C1025 C1026 C1027 C1028 C1029 C1030 C1031 C1032 C1033 C1034 C1035 C1036 C1037 C1038 C1039 C1040 C1041 C1042 C1043 C1044 C1045 C1046 C1047 C1048 C1049 C1050 C1051
11
................................................................................................................................... 341 ................................................................................................................................... 342 ................................................................................................................................... 342 ................................................................................................................................... 342 ................................................................................................................................... 342 ................................................................................................................................... 342 ................................................................................................................................... 342 ................................................................................................................................... 342 ................................................................................................................................... 343 ................................................................................................................................... 343 ................................................................................................................................... 343 ................................................................................................................................... 343 ................................................................................................................................... 343 ................................................................................................................................... 343 ................................................................................................................................... 343 ................................................................................................................................... 344 ................................................................................................................................... 344 ................................................................................................................................... 344 ................................................................................................................................... 344 ................................................................................................................................... 344 ................................................................................................................................... 344 ................................................................................................................................... 344 ................................................................................................................................... 344 ................................................................................................................................... 345 ................................................................................................................................... 345 ................................................................................................................................... 345 ................................................................................................................................... 345 ................................................................................................................................... 345 ................................................................................................................................... 345 ................................................................................................................................... 346 ................................................................................................................................... 346 ................................................................................................................................... 346 ................................................................................................................................... 346 ................................................................................................................................... 346 ................................................................................................................................... 346 ................................................................................................................................... 346 ................................................................................................................................... 346 ................................................................................................................................... 346 ................................................................................................................................... 346
11
12
DAQFactory User's Guide C1052 C1053 C1054 C1055 C1056 C1057 C1058 C1059 C1060 C1061 C1062 C1063 C1064 C1065 C1066 C1067 C1068 C1069 C1070 C1071 C1072 C1073 C1074 C1075 C1076 C1077 C1078 C1079 C1080 C1081 C1082 C1085 C1086 C1087 C1088 C1089 C1090 C1091 C1092 ................................................................................................................................... 347 ................................................................................................................................... 347 ................................................................................................................................... 347 ................................................................................................................................... 347 ................................................................................................................................... 347 ................................................................................................................................... 347 ................................................................................................................................... 347 ................................................................................................................................... 347 ................................................................................................................................... 347 ................................................................................................................................... 347 ................................................................................................................................... 348 ................................................................................................................................... 348 ................................................................................................................................... 348 ................................................................................................................................... 348 ................................................................................................................................... 348 ................................................................................................................................... 348 ................................................................................................................................... 348 ................................................................................................................................... 348 ................................................................................................................................... 348 ................................................................................................................................... 349 ................................................................................................................................... 349 ................................................................................................................................... 349 ................................................................................................................................... 349 ................................................................................................................................... 349 ................................................................................................................................... 349 ................................................................................................................................... 349 ................................................................................................................................... 349 ................................................................................................................................... 349 ................................................................................................................................... 350 ................................................................................................................................... 350 ................................................................................................................................... 350 ................................................................................................................................... 350 ................................................................................................................................... 350 ................................................................................................................................... 350 ................................................................................................................................... 350 ................................................................................................................................... 350 ................................................................................................................................... 350 ................................................................................................................................... 350 ................................................................................................................................... 351
Contents C1093 C1094 C1095 C1096 C1097 C1098 C1099 C1100 C1101 C1102 C1103 C1104 C1105 C1106 C1107 C1108 C1109 C1110 C1111 C1112 C1113 C1114 C1115 C1116 C1117 C1118 C1119 C1120 C1121 C1122 C1123 C1124 C1125 C1126 C1127
13
................................................................................................................................... 351 ................................................................................................................................... 351 ................................................................................................................................... 351 ................................................................................................................................... 351 ................................................................................................................................... 351 ................................................................................................................................... 351 ................................................................................................................................... 351 ................................................................................................................................... 352 ................................................................................................................................... 352 ................................................................................................................................... 352 ................................................................................................................................... 352 ................................................................................................................................... 352 ................................................................................................................................... 352 ................................................................................................................................... 352 ................................................................................................................................... 352 ................................................................................................................................... 352 ................................................................................................................................... 353 ................................................................................................................................... 353 ................................................................................................................................... 353 ................................................................................................................................... 353 ................................................................................................................................... 353 ................................................................................................................................... 353 ................................................................................................................................... 353 ................................................................................................................................... 353 ................................................................................................................................... 353 ................................................................................................................................... 353 ................................................................................................................................... 354 ................................................................................................................................... 354 ................................................................................................................................... 354 ................................................................................................................................... 354 ................................................................................................................................... 354 ................................................................................................................................... 354 ................................................................................................................................... 354 ................................................................................................................................... 354 ................................................................................................................................... 354
13
1 Introducing DAQFactory
1 Introducing DAQFactory
15
1 Introducing DAQFactory
1.1 End User License Agreement
AzeoTech, Inc., ("AzeoTech") licenses the accompanying software to you (referred to herein as "you" or the "end user") only upon the condition that you accept all of the terms contained within this Agreement relevant to the software. Please read the terms carefully before continuing the installation, as pressing the "Yes" button will indicate your assent to them. If you do not agree to these terms, please press the "No" button to exit the install, and return the full product with proof of purchase to AzeoTech within thirty (30) days of purchase.
16
different version of DAQFactory is subject to Section II(C) below. Upon payment for a non-Express version of DAQFactory, AzeoTech provides the end user with a code that enables the appropriate features of the software. 2. You may distribute the Evaluation Software to third parties for evaluation purposes only. Such copies shall be subject to the relevant terms and conditions of this Agreement in the same manner as if distributed directly by AzeoTech. B. DAQFactory-Developer. The following provisions apply only to the use and license of DAQFactory-Developer and the use and license of DAQFactory Runtime in conjunction with DAQFactory-Developer and all documents and applications created with DAQFactory-Developer. 1. If you have purchased a license for DAQFactory-Developer, AzeoTech grants you permission to distribute your created documents and applications, together with DAQFactory Runtime, to third parties without a licensing fee. In exchange, you agree to be bound by all of the relevant terms and conditions set forth in this Agreement. 2. All third party users and recipients of documents or applications created with DAQFactory-Developer are bound by all of the terms and conditions of this agreement, and are strictly prohibited from distributing DAQFactory Runtime absent their own purchase of a license for DAQFactory-Developer. In addition, third party users and recipients are strictly prohibited from using DAQFactory Runtime to run applications other than those created with DAQFactory-Developer, except upon their purchase of a license for DAQFactory Runtime from AzeoTech. 3. Neither you nor third party users or recipients are permitted to create generic data acquisition applications using DAQFactory-Developer that would directly compete with DAQFactory or any other AzeoTech software product. This includes, but is not limited to, generic strip chart recorders, data loggers and PID loop controllers. C. DAQFactory Express. The following provisions apply to the use and license of DAQFactory Express, a version of DAQFactory enabled once the evaluation period ends, or a separate software product available from AzeoTech and often provided to you in association with hardware from a hardware manufacturer. 1. DAQFactory Express is not "Evaluation Software" as defined in Section II(A) above, and accordingly, there is no 25 day time limit on its use and license. Despite the fact that you have not paid a licensing fee for this product, it is licensed software, subject to the relevant provisions of this Agreement. You are not permitted to distribute DAQFactory Express in any form to third parties, or upload this program onto the internet or a network which may be accessed by unlicensed third parties. 2. If you have received DAQFactory Express in conjunction with hardware from a hardware manufacturer, your license for DAQFactory Express is provided to you free of charge, by AzeoTech, through the hardware manufacturer. This license is strictly limited to your use of DAQFactory Express in conjunction with the accompanying hardware, and this program may not be used on any computer or device which does not contain the accompanying hardware. If you are a hardware manufacturer, you must enter into a separate agreement with AzeoTech to distribute DAQFactory Express licenses. DAQFactory Express cannot be distributed for free by simply including it with hardware.
1 Introducing DAQFactory
17
PRECAUTIONS TO GUARD AGAINST COMPUTER VIRUSES, BUT DOES NOT WARRANT THAT THE SOFTWARE PROVIDED WILL BE WITHOUT ANY COMPUTER VIRUSES. YOU ASSUME ALL RESPONSIBILITY FOR ACHIEVING YOUR INTENDED RESULTS, TAKING PROPER PRECAUTIONS TO GUARD AGAINST COMPUTER VIRUSES, AND FOR THE USE AND RESULTS OBTAINED FROM THE SOFTWARE. D. No Liability for Damages. In no event shall AzeoTech or its suppliers be liable for any damages whatsoever, including, without limitation, any special, consequential, indirect or similar damages, including damages for loss of business profits, lost data arising out of the use or inability to use the software, business interruption, loss of business information, or any other pecuniary loss, arising from or out of the use of or inability to use the AzeoTech software, even if AzeoTech has been advised of the possibility of such damage. In any case, AzeoTechs entire liability under any provision of this Agreement shall be limited to the amount actually paid by you for the software. The disclaimers and limitations set forth herein will apply regardless of whether you accept the software. Because some states/jurisdictions do not allow the exclusion or limitation of liability for consequential or incidental damages, the above limitation may not apply to you. E. WARNING. AZEOTECHS SOFTWARE IS NOT DESIGNED FOR COMPONENTS OR TESTING FOR A LEVEL OF RELIABILITY SUITABLE FOR USE IN OR IN CONNECTION WITH ANY APPLICATION WHERE MALFUNCTION OF HARDWARE OR SOFTWARE COULD RESULT IN INJURY OR DEATH, OR AS CRITICAL COMPONENTS IN ANY LIFE SUPPORT SYSTEMS WHOSE FAILURE TO PERFORM CAN REASONABLY BE EXPECTED TO CAUSE SIGNIFICANT INJURY OR DEATH. THE SOFTWARE MUST NEVER BE USED FOR ANY PURPOSE THAT, IF THE SOFTWARE FAILED, COULD CAUSE INJURY OR DEATH TO ANY PERSON. IN ANY APPLICATION, INCLUDING THE ABOVE, RELIABILITY OF OPERATION OF THE SOFTWARE CAN BE IMPAIRED BY ADVERSE FACTORS, INCLUDING BUT NOT LIMITED TO THE FLUCTUATIONS IN ELECTRICAL POWER SUPPLY, COMPUTER HARDWARE MALFUNCTIONS, COMPUTER VIRUSES, COMPUTER OPERATING SYSTEM SOFTWARE FITNESS, FITNESS OF COMPILER AND DEVELOPMENT SOFTWARE USED TO DEVELOP AN APPLICATION, INSTALLATION ERRORS, SOFTWARE AND HARDWARE COMPATIBILITY PROBLEMS, MALFUNCTIONS OR FAILURES OF ELECTRONIC MONITORING OR CONTROL DEVICES, TRANSIENT FAILURES OF ELECTRONIC SYSTEMS (HARDWARE AND/OR SOFTWARE), UNANTICIPATED USES OR MISUSES, OR ERRORS ON THE PART OF THE USER OF APPLICATIONS DESIGNER (THE ADVERSE FACTORS SUCH AS THE FOREGOING EXAMPLES ARE HEREAFTER TERMED "SYSTEM FAILURE"). ANY APPLICATION WHERE A SYSTEM FAILURE WOULD CREATE A RISK OF HARM TO PROPERTY OR PERSONS (INCLUDING THE RISK OF BODILY INJURY OR DEATH) SHOULD NOT BE RELIANT SOLELY UPON ONE FORM OF ELECTRONIC SYSTEM DUE TO THE RISK OF SYSTEM FAILURE. TO AVOID DAMAGE, INJURY OR DEATH, THE USER OR APPLICATION DESIGNER MUST TAKE REASONABLY PRUDENT STEPS TO PROTECT AGAINST SYSTEM FAILURES, INCLUDING BUT NOT LIMITED TO BACK-UP OR SHUT DOWN MECHANISMS. BECAUSE EACH END-USER IS CUSTOMIZED AND DIFFERS FROM AZEOTECH TESTING PLATFORMS AND BECAUSE A USER OR APPLICATION DESIGNER MAY USE AZEOTECH PRODUCTS IN COMBINATION WITH OTHER PRODUCTS IN A MANNER NOT EVALUATED OR CONTEMPLATED BY AZEOTECH, THE USER OR APPLICATION DESIGNER IS ULTIMATELY RESPONSIBLE FOR VERIFYING AND VALIDATING THE SUITABILITY OF AZEOTECH PRODUCTS WHENEVER AZEOTECH PRODUCTS ARE INCORPORATED IN A SYSTEM OR APPLICATION, INCLUDING, WITHOUT LIMITATION, THE APPROPRIATE DESIGN, PROCESS AND SAFETY LEVEL OF SUCH SYSTEM OR APPLICATION.
IV. COPYRIGHT
All title and copyrights in and to AzeoTech software, including but not limited to any images, photographs, animations, video, audio, music, text, and "applets" incorporated into the software, any printed materials, and any copies of the software are owned by AzeoTech and its suppliers. The software is protected by U.S. Copyright laws and international treaty provisions. Therefore, you must treat the software like any other copyrighted material, subject to the terms of this agreement.
18
direct product of the software (the foregoing collectively referred to as the "Restricted Components"), to any country, person, entity, or end user subject to U.S. export restrictions. You specifically agree not to export or reexport any of the Restricted Components (i) to any country to which the U.S. has embargoed or restricted the export of goods or services, which currently include, but are not limited to Cuba, Iran, Iraq, Libya, North Korea, Sudan, and Syria, or to any national or any such country, wherever located, who intends to transmit or transport the products back to such country; (ii) to any end user who you know or have reason to know will utilize the Restricted Components in the design, development or production of nuclear, chemical or biological weapons; or (iii) to any end user who has been prohibited from participating in U.S. export transactions by any federal agency of the U.S. Government. You warrant and represent that neither the Bureau of Export Administration (BXA) nor any other U.S. Federal agency has suspended, revoked or denied your export privileges.
1.2 Acknowledgements
We would like to thank the following companies for their excellent components and tools which are in use by DAQFactory or were used to help create DAQFactory. Dundas Software: For their Ultimate Grid MFC, Ultimate Toolbox, Ultimate Edit, and M++ math libraries. BCGSoft Ltd.: For their BCGControl application framework. Gigasoft, Inc.: For their ProEssentials graphing component. OptiCode - Dr. Martin Sander Software Development : For their curve fitting routine in the OptiVec math library. Software Toolbox, Inc: For their OPCData component and Symbol Factory image library. PJ Naughter: For his tray, single instance, web server, email, FTP and many other components. Concept Software, Inc: For their Protection Plus copy protection. eHelp Corporation: For their RoboHelp help authoring environment and tools. Red Hat, Inc.: For their foreign function interface code. Neil Hodgson: For the scintilla code editor Here are the copyright notices for some of the above products. This software contains material that is 1994-2000 DUNDAS SOFTWARE LTD., all rights reserved. Copyright BCGSoft Ltd. 1998-2001. All rights reserved Copyright (C) 2001 Gigasoft, Inc. All rights reserved Copyright 1998-2001 OptiCode - Dr. Martin Sander Software Development Copyright Software Toolbox, Inc., 1996-2000, All Rights Reserved Worldwide Copyright (c) 1996 - 2001 by PJ Naughter Copyright 1997-2000 Concept Software, Inc. Copyright (c) 1996-2003 Red Hat, Inc.
1 Introducing DAQFactory
19
Copyright 1998-2003 by Neil Hodgson <[email protected]> And do not forget that DAQFactory, which includes DAQFactory and associated files (including this one) are Copyright 2001-2006 AzeoTech, Inc. All rights reserved worldwide. AzeoTech and DAQFactory are a registered trademark of AzeoTech, Inc.
The following notice is required for the Red Hat foreign function interface license: libffi 2.00-beta - Copyright (c) 1996-2003 Red Hat, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software''), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. The following notice is required for the Scintilla editor: Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. NEIL HODGSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL NEIL HODGSON BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
For DAQFactory:
Any computer capable of running Windows 2000 Pro or newer. We suggest at least a Pentium 90, and preferably much more. The program is designed to be responsive even under processor strain, however, the refresh rate of graphs and images will be greatly reduced on slower processors. 30 Meg of free hard disk space. Enough memory to run the operating system plus a minimum of 8 meg on top of that. Generally, the more you have, the more you will be able to take advantage of DAQFactory's capabilities. The exact memory requirements depend on the screen resolution. DAQFactory uses a triple background painting algorithm to make it very responsive even when drawing large graphs or images. This requires three copies of the screen to be kept in memory. This means that if you are running DAQFactory in 1024x768 resolution with 32 bit color you will need at least 12 meg of extra memory just for these screen buffers. If you are running DAQFactory at 1600x1200 with 32
20
bit color, the memory requirements for these buffers jumps up to 32 meg. In addition to this, DAQFactory keeps the history of your data in memory for quick, real-time calculations. Each data point in memory uses 16 bytes. To remember an hours worth of data on a single channel, read at 1 second intervals you will need 60K. Video capable of 800x600 resolution. 1024 x 768 is strongly suggested. If DAQFactory is only going to be used as an HMI, it is possible to setup the DAQFactory screens on one computer and transfer the file to another computer that may not be able to achieve 800 x 600. In this case, DAQFactory will operate at almost any resolution. We suggest DAQFactory Runtime for this type of application. Windows 2000 Pro or newer. You cannot run the program on Windows 95, 98, Me, NT 4.00, NT 3.51, CE, or any other lesser version of Windows. Internet Explorer version 4 or greater must be installed for the help system.
1 Introducing DAQFactory
21
3) Keep your history lengths on your channels at smaller values. This is usually only an issue if you have histories above 20,000 or so on slow computers. On newer computers, history lengths in above 100,000 are easily possible. If you need larger histories or persistence lengths, make sure and subset all your data before manipulating it. For example, if you are doing a graph, don't just put the channel name, but rather subset to the x axis scaling. 4) Check your sequences for reasonable loop times, and whenever possible, use events instead of sequences with loops. For example when monitoring an input for a particular value, you should use that channel's event instead of creating a sequence loop.
22
4. Go to www.azeotech.com/unlock.html and enter in the code displayed in the window above (yours will be different than 4480588) and your 15 letter key. Make sure you enter the code correctly into the web site. When you click Get Unlock Code on the web site, a numeric unlock code and your serial number will be provided. Enter these two numbers into the edit boxes in the Manual Unlock window then click OK. 5. Your product should now be unlocked. If you have no Internet connection available, contact your vendor and they will be able to provide you with the manual unlock codes. The unlock codes are specific to the machine you installed DAQFactory on. There is a different unlock code for each version of DAQFactory.
1 Introducing DAQFactory
23
24
The strtodouble() function was updated to return NaN() if the string started with an invalid character (i.e.
strtodouble("ab")) instead of 0. As always, if the string starts with a number but then contains an invalid character, the string is still properly converted up to that point: strtodouble("123ab") returns 123.
On that same note, the Mean / Sum / Max / Min functions have been updated to handle NaNs properly which may
cause existing calcs to change if you are using these functions and NaNs in your data.
Another bug fix that may cause calcs to change is when subsetting by time. Older releases would incorrectly
include one point past the end time. New releases properly subset the date range specified.
One bug fix in 5.30 may cause problems with earlier documents if you have a workaround in place. In previous
versions, when doing the AddValue() function on a channel with a value that had more than one row, the rows would be flipped before being added, so: after MyChannel.AddValue(Var.x), Var.x[0] would not equal MyChannel[0]. This has been fixed so that the values are added in the right order.
The format() function now accepts \ notation for carriage return, line feed and tab. This means that if you have a
regular \ in a format() function, you'll need to add a second backslash: \\. This does not affect regular string assignment, so x = "c:\myfile.csv" is still valid, but x = Format("c:\myfile%d.csv",y) needs to be changed to x = Format("c:\\myfile%d.csv",y) The Runtime version of DAQFactory is now a part of the development version and no longer a separate executable. This has a lot of advantages (see the section on Runtime), but will require some changes. First, you'll need to replace your DAQFactory Runtime installation with a regular DAQFactory installation (licensing will remain the same, so just install into the same directory and change your shortcuts). The Runtime also will no longer automatically load Runtime.ctl, so you will have to specify the file name in a Windows shortcut.
DAQFactory.exe: Since DAQFactory Acquire is now part of DAQFactory Control, we have simply named the
program DAQFactory and changed the executable from Control.exe to DAQFactory.exe. Please make sure your shortcuts point to the correct executable and that you are running release 5. You can check your release by going to Help - About DAQFactory. The runtime has also been renamed DAQFactoryRuntime.exe.
Logging: Data logging in DAQFactory release 5 has been completely revamped. User feedback on the
difficulties in importing logged data into other programs was the impetus for these changes. All old forms of data logging including binary forms and local condition logging have been removed. Now all data logging is performed using logging sets. Please see the logging chapter for a complete description.
1 Introducing DAQFactory
25
Sequences: Sequences have been made into a complete scripting language, giving them much more power.
Old sequences will load correctly and be correctly translated, however error handling in the new sequences is different. In old versions of DAQFactory, if an error occurred in a step, the step was simply skipped. This often made it difficult to figure out why a sequence was not performing the way it should, since errors were not apparent. The new sequences use a C++ type error handling mechanism. Errors must be caught and processed or the sequence will stop and display an alert. Because of this, all old sequences will load with the command ignore (all) added. This will cause all errors to be ignored similar to the older releases.
Symbols (formally images): To better handle 3rd party symbols and properly scale the symbol factory
symbols, symbol scaling has been fixed to display the symbol within the components rectangle. This will cause all of your current symbols to be scaled slightly differently. This can be fixed easily by resizing your symbols.
Point(): The Point() function now returns a 0 index array instead of 1 indexed array. Relative time subsetting: is no longer supported. Replace with SysTime() - x notation: MyChannel
[SysTime()-5,SysTime()-2]
Case sensitivity: DAQFactory is no longer case sensitive except when comparing string values. This will only
affect older documents if you have two objects with the same name but spelled with different case: for example, MyChannel and mychannel. If so, rename one of the objects. Also you should reset your menus and keyboard shortcuts. To do this, select Tools-Customize... from the main menu. Go to the Toolbars, Keyboard and Menu pages and click Reset All on each of them (Reset on the menu page). Note: Be sure to keep a backup of your original document before upgrading to the new release.
26
Title Bar: The area at the top of the window, common to most all Windows applications. This does nothing out of
the ordinary, except that it will flash to get your attention if an alert event occurs.
Main menu: The menu area just below the title bar, also common to many Windows applications. Most of the
functions of DAQFactory are available through these menus. Many of the options may appear grayed out until certain events have occurred.
Toolbars: These offer quick access to common features. Two toolbars are initially displayed for the most
common items. There are several other toolbars available as well. Click on View in the main menu to activate them. You can even customize the toolbars if desired. Go to Tools-Customize... to do so.
Pages: This is the main area of the screen, which is completely white when you start DAQFactory for the first
time. A page is where you can drop in various components to display your data in numerous different ways, including schematics of your process, or complicated graphs. DAQFactory can have an infinite number of pages for displaying different parts of your data, or displaying your data in different ways. Switching between pages can be as simple as pressing a key. You can even overlay multiple pages to keep important data always on the screen, or popup pages in separate windows.
Status bar: The status bar is the area along the bottom of the window and contains quick help information on
menu items and toolbar buttons. As you move the mouse over these items, a slightly longer explanation of the meaning of the menu item or button will be displayed. To the right side of the status bar are three other panes. The first one displays the position on the screen in pixels. When your mouse cursor is over a graph, it will display the coordinates of your mouse cursor within the graph in graph coordinates instead. Next is an alert panel. This, like the title bar, will flash when an alert event occurs. Finally, there is a safe panel. This illuminates when you are running in safe mode.
1 Introducing DAQFactory
27
The rest of the window contains what Windows calls Docking Control Bars. These are windows that can be "docked" to the various sides of the main DAQFactory window, or dragged elsewhere on the screen in detached mode. DAQFactory control bars also can be auto-hidden, and most are in this state by default. An auto-hidden control bar displays a tab most of the time, but if you click on the tab, or even just place you mouse cursor on the tab, the window will appear. You can then work with the window. Once you click outside the window, it will auto-hide back to the tab. Any of the control bars can be put in auto-hide mode, or switched out of it. To do so, click on the thumbtack at the top right corner of the control bar window.
Workspace: This is where most of the background parameters, such as connections, channels, conversions and
sequences are accessed. These parameters are displayed in the workspace in tree form to quickly identify which channels correspond to which connections, etc. A list of the display pages are also displayed on the tree. This is a floating window that by default is docked to the right side of the screen, but can be dragged anywhere on the screen or docked to other sides. If you close this window, you can reopen it from View in the main menu.
Help: This is another floating window that contains help information. By default, this bar is auto-hidden along the
right side. Simply click on the tab to make it appear. If follow-me help is enabled, help will also appear under most popup windows. Follow-me help is enabled by default and can be turned off and on from View-Help-Follow Me Help in the main menu.
Command / Alert: DAQFactory contains a command line interface that allows you to execute script functions,
or view your data. Use of this interface is optional, but often useful for those users who prefer this type of interface. In addition to the ability to enter commands and see the result, this window displays error messages. All messages remain in the window. To clear the alert window, right click on the window and select Clear Window. You can also copy out of the results part of the window by selecting the text, right clicking and selecting Copy.
Watch: This is another floating window that provides a table for displaying current values of any sort of
expression. This is typically used to debug sequences. The table contains 100 lines. Enter an expression in the left Watch column and the result of the expression is displayed in the right Value column. This value is updated twice a second.
Comm Monitor: The Comm Monitor window allows you to easily monitor serial and Ethernet communications
from a docking window. The window works almost identical to the monitor window described in the chapter on serial and Ethernet communications, except that to select the communications port to monitor, pause the monitor and adjust the other settings, you should right click for a popup menu. At the top of this window is a single line edit box where you can type text to be output to your communications port. Below this is a larger area showing the communications. Please see the section on serial and Ethernet communications for more details. You can also copy out of the monitor part of the window by selecting the text, right clicking and selecting Copy.
Notes: This window displays quick notes. Quick notes provide a virtual lab notebook. You can enter any sort of
information about your experiment or process and the note will be time stamped with the current computer time. The notes can be saved to disk as well with your data. There are several other floating windows that are not initially displayed. They can be displayed by selecting the appropriate window from under View in the main menu.
On Screen Keyboard: If you are running on a touch screen or a computer without a keyboard, there is an on
screen keyboard that can be displayed. This also enables the on screen keyboard in other areas of DAQFactory. The on screen keyboard cannot be used for creating your application as it does not function in the properties windows of page components. This window is normal not displayed. To display it, go to View in the main menu.
Channels:
A channel typically is a single I/O location, be it analog to digital, digital to analog, digital out, digital in, counters, a spectrum, an image, or any other type of data. For those in the automation world, a channel is equivalent to a tag. 1 Introducing DAQFactory1.11 DAQFactory's User Interface
28
There can also be channels that contain calculated values such as results from analysis functions, or even calculated formulas. These are discussed a bit more in virtual channels. To make life easier, the details of which I/O channel number and device correspond to what channel only need by entered once. Each channel is given a name, and after defining the I/O associated with that name, only this name is required throughout the rest of the program. There is no need to remember that ambient_temperature channel is attached to Acme I/O board, device #3, channel #2! Channels have a history. This is a list of values with time tagged to each value. The most recent values are always the first values in the history progressing back in time.
Virtual Channels:
Virtual channels provide a location for storing values that do not have an I/O associated with them. This can be results from analysis calculations, captured values from graphs, calculated expressions, or values set from a sequence. They are called virtual channels because they can be used anywhere a channel is used within the DAQFactory program and contain a history like a channel. Virtual channel's usefulness has decreased as DAQFactory has moved forward. Typically you will want to use regular channels and the AddValue() function to store historical values, or variables to store scalar values.
Variables:
Variables are simply locations in memory for storing values. They are not associated with any I/O and do not have a history, though they can be an array of values. Variables are typically used in sequences, but can also be used as state flags or anything else you may come up with.
Conversions:
Most I/O devices output their values in rather abstract units, such as a number between 0 and 65535, 0 to 10 volts, or 4 to 20mA. Conversions provide a way to convert these arbitrary units into something more tangible and appropriate. For example, you may have a pressure transducer that has a range of 0 to 500 psi which corresponds to 0 to 10V output. Your A/D channel outputs 0 to 4096 corresponding to 0 to 10V. You could create a conversion to convert that 0 to 4096 value into a 0 to 500 psi value. The conversion would look something like this: Value/4096*500 This is an example of a simple conversion. You can make much more complicated conversions to take into account calibration curves etc. Because you will often have multiple Channels reading similar devices (multiple identical pressure transducers in this example), the conversions are kept in a list by name, and when you need to apply a conversion to a channel, you simply select the name instead of having to retype the formula multiple times. Conversions are especially useful on output channels. They allow you to specify your output value in useful units rather than the units required by the output channel. Here the conversion expression is actually reversed. The expression should convert useful units to I/O units.
Expressions:
Conversions are not the only place you can enter in calculations. In fact, conversions are typically only used to get things into proper units. While not really an object, expressions are calculations that you can use in various places throughout DAQFactory. In fact, the formula you enter in a conversion is actually an expression. Expressions can be as simple as a constant or as complex as you need, acting on single data points or arrays of points. When entering expressions, DAQFactory provides syntax coloring and an intelligent drop down box that displays channels, formulas and other things you may want use in your expression so you don't have to remember everything. Any edit box within DAQFactory that displays in color can take an expression. Expressions are used to display calculated values, to graph calculations, to set ranges, to control data logging and in many other locations.
Sequences:
Sequences provide a powerful scripting language to automate your project. Sequences have many uses including performing automatic calibrations, monitoring your system for certain conditions and performing actions based on
1 Introducing DAQFactory
29
those conditions, or even replacing programmable logic controllers or other hardware devices with software control. Sequences are easy to setup and maintain. Multiple sequences can be run at multiple times. Sequences can also be used as user functions in expressions. Sequences can even be setup to start automatically when the DAQFactory starts, creating a completely automated system!
PID Loops:
PID is an effective algorithm for controlling closed loop systems. The algorithm attempts to keep a "Process Variable" (PV), such as temperature, at a particular "Set Point" (SP) by controlling an "Output Variable" (OV). The algorithm uses three parameters: proportion (P), integral (I), and derivitive (D). DAQFactory includes an autotuning mechanism to help you determine the best P, I and D parameters for your system. You can create as many PID loops as your computer will allow, all of which can run simultaneously.
Logging Sets:
Logging sets provide the mechanism for logging your data to disk. You can create multiple logging sets to log all or part of your data in several different formats with different options. Logging sets can be started and stopped at any time and can be run simultaneously. Currently, DAQFactory supports logging to delimited ASCII, ODBC database, and 3 binary modes. Delimited ASCII mode is easily read by most other programs such as Excel and the recommended format unless you have a back-end SQL database.
Export Sets:
Export sets are similar to logging sets but do not run continuously. While logging sets log channels directly (or calculated values through a manual mechanism), export sets log the results of expressions. The options for export sets are very similar to logging sets. Logging sets are typically used for continuous logging. Export sets are used when you want to conditionally log one line at a time, or you want to log data that has already been acquired.
Alarms:
Alarms provide a way for you to detect out of boundary conditions in your system even if your system returns to normal. For example, if you want to know if your system gets above 100C, you can use an alarm to monitor the temperature and it will trigger if the system goes above 100C even if it then immediately returns under 100C. Alarms display until manually acknowledged and can be logged in an ASCII file or ODBC database. You can have multiple alarms watching for any number of events in your system.
Pages:
Within the DAQFactory program you can have multiple screens containing graphs, images, values, and other screen components that provide the user interface for your device. Each screen is in a basic way considered a page. Pages, however are more like overlays than a simple screen. You can easily display multiple pages overlaid on top of each other on a single screen. This is most useful when you have certain data you always want to be visible. You can place this data on a page and have that page overlaid on top of all the other pages. Pages can also be made to popup in a separate window. The window can either be modal, meaning the user cannot access any other window until the popup is closed, or modeless, a floating window that allows access to the rest of DAQFactory. Modeless popup pages are a useful alternative to overlaid pages. One very powerful feature of DAQFactory is the ability to design your Pages while your application is running. No quitting your experiment or process halfway though when you realize that you need just one more graph. You can add, remove, or change any component at any time!
Components:
Components are the windows to your data. There are 1040 components that allow you to create a completely custom user interface for your application. Components can be placed anywhere on pages enabling you to create any screen design you would like, from a simple summary of your data, to a complete virtual instrument or factory. All the Components have many options that control how the Component displays itself and what action is performed
30
Connections:
A Connection identifies where data is coming from. Data can come from various places: A local connection, namely from within DAQFactory itself. The virtual channel list, or V Connection containing calculated data, results from calculations, and captured data. Another copy of DAQFactory located on the same computer, most likely in Acquire mode. A copy of DAQFactory located remotely, either in Acquire or DAQFactory mode.
A single copy of DAQFactory can have multiple connections to any of the above sources, enabling the user to monitor multiple locations and data streams from a single spot. Remote connections are established in DAQFactory and consist of a name, a TCP/IP address or URL of the copy of DAQFactory it is connecting to, and some other miscellaneous information that is discussed later. With the exception of the V connection, each connection has its own alarm, channel, conversion, export, logging, PID and sequence list.
2 Guided Tour
II
32
2 Guided Tour
2.1 Tour Overview
In this tour we will show you how to use DAQFactory to perform data acquisition, display your data, both locally and on the web, and logging, and give you the base to proceed comfortably through the rest of the manual or explore DAQFactory on your own. We recommend performing all the steps on your computer as you read through this tour. To use this tour you do not have to have any data acquisition hardware. This tour uses the test device which generates sine waves.
2 Guided Tour
33
2. In the Channel Table View that appears, click on the Add button at the top. This creates a new row where we will enter the information for our first channel. 3. In the new row of the table, enter Pressure in the Channel Name column. All channels must have a name. You can assign any name you want to your channels as long as they are unique, start with a letter and only contain letters, numbers or the underscore "_". 4. In the second column, Device Type, select Test from the drop down list. The device type determines which type of device you wish to communicate with. This can be a specific manufacturer, a specific device, or a generic communications method such as OPC or serial. 5. In the third column, D #, leave the cell set at 0. The device # is only used by some devices and has different meanings depending on the device. 6. In the fourth column, I/O Type, select A to D. Most devices have several different types of data coming in or going out. The I/O type determines which type of data you desire. For example, many DAQ boards contain both A to D and D to A channels. The I/O Type determines which of these you wish to communicate with for this channel. I/O Types are not fixed types and different devices will have different choices available. 7. In the fifth column, Chn #, enter 1. Most devices have several I/O points per I/O type. The channel number determines which I/O point this channel refers to. 8. Leave the rest of the columns in their default setting. One important item to mention is the sixth column, Timing. For input channels this determines how often the input is read from the device. The interval provided here is in seconds. For now, we are going to leave it set at 1, or one new reading per second. In general you will never want to make this number smaller than 0.01. To acquire data at faster speeds requires hardware paced acquisition which, if supported by your device, is described in the section on your device. 2 Guided Tour2.5 Creating Channels
34
9. Click on the Apply button at the top of the screen. The changes you make are not implemented by DAQFactory until you click Apply. If you do not want to keep your changes, you can click Discard. Once you click Apply, DAQFactory will start taking data from the test device, D#0, I/O Type A to D, Channel #0, and place that data in the "Pressure" channel.
10. Click on the + sign next to CHANNELS in the workspace. The + sign appeared when you hit Apply. Clicking on it displays the channels you've created as separate items in the workspace. 11. Click on Pressure listed under CHANNELS in the workspace. This will display the channel view for the channel Pressure. The channel view displays the configuration information for a single channel. In general, it is quicker to create your channels in the channel table, but the channel view provides space for some extra details. 12. In the Channel View that appears, click on the Graph tab. The channel view also provides a quick graph and table to view your incoming data. This can be used to confirm that data is being acquired and that you are reading the correct data. You should see a sine wave displayed in the graph. You have just confirmed that you are acquiring data on your pressure channel.
2 Guided Tour
35
13. If you'd like to see the table, click on the Table tab.
You are now taking data. In the next section we'll display it on our own custom screens.
For more information on channels and the various parameters available, see the chapter on Channels and Conversions.
36
3. Right click on the new component and select Properties... All of the screen components have different properties windows for configuring the look of the component and telling the component what data to display. 4. Next to Caption:, enter Pressure. The caption is what is displayed in front of your value. A colon is automatically added when displayed. 5. Next to Expression:, enter Pressure[0]. Expressions are actually formulas that you can enter to display calculated data. In this case, the formula simply requests the most recent data point of the channel pressure. The [0] indicates the most recent data point. If you did [1] you'd get the next most recent data point and so forth back to the History length of the channel, which we left in the default of 3600. You could just as easily put Pressure[0] * 10 if you wanted to display the channel's value times ten.
2 Guided Tour
37
NOTE: A common error is to use () instead of [] for subsetting. Although this works in some cases, it does not work in all, nor do we guarantee that it will continue to work in newer versions. 6. Click on OK. Now the screen should display Pressure: 0.324 V with a changing number. This is the current value in the pressure channel we created earlier. Feel free to open the properties window again and play with the units, font and other settings. 7. While holding the Control key, click on the first Variable Value component. This will select the component, as indicated by the shaded rectangle surrounding it. 8. While holding the Control key, click and drag the Variable Value component to a new location on the screen. This allows you to move the component around the screen. The next steps will not work in DAQFactory Express because it doesn't include gauges. Consider upgrading to any of the paid versions of DAQFactory to get gauges and thirty some other controls, among other things. 9. Right click somewhere else on the screen away from the displayed component and select Gauges-Angular.
10. Right click on the new component and select Properties... to open its properties window. 11. For the expression, enter Pressure[0] * 10. As we mentioned before, expressions are actually formula so wherever there is an expression we enter in calculations. This particular one simply takes the most recent value of the pressure channel and multiplies it by 10. 12. For the Range, enter -10 to 10. Since pressure is simply a sine wave of amplitude one, and we're multiplying this by 10, the range this component will see is -10 to +10.
38
13. Click OK. The gauge will now be scaled from -10 to 10 and the gauge arrow will move with the value of pressure. Notice how the first screen component still displays values from -1 to 1. Both of these components are independent of each other. 14. While holding the Control key, click on the first Variable Value component. This will select the component, as indicated by the shaded rectangle surrounding it. 15. While holding the Control key, click and drag the Variable Value component to a new location on the screen. This allows you to move the component around the screen. Try the same thing with the gauge. 16. While holding the Control key, click on the gauge. Square dots will appear at the corners of the gauge. Click and drag these dots to resize the graph. The gauge is a resizable component and displays square black dots around the selection rectangle for resizing. The Variable Value component automatically sizes to its contents so does not display the dots.
2 Guided Tour
39
You now know how to display your data using several different screen components. Next we will learn how to use the graph to display historical data.
In the mean time, feel free to play with other similar components if you'd like. When done, you can delete them by selecting the component (Control - Click) and then right clicking and selecting Delete Component. For more information on page components and creating your user interface, see the chapter entitled Pages and Components. For more information on expressions and the functions available for use in expressions, see the chapter entitled Expressions.
40
3. Next to Y Expression: type Pressure. The Y expression is an expression just like the others we have seen so far. The difference is that a graph expects a list (or array) of values to plot, where in the previous components we have only wanted the most recent value. By simply naming the channel in the Y expression and not putting a [0] after it, we are telling the graph we want the entire history of values stored in memory for the channel. The history length, which determines how many values are kept in memory and therefore how far back in time we can plot is one of the parameters of each channel that we left in its default setting of 3600.
4. Leave all the rest in their default settings and click OK. You should now see the top half of a sine wave displayed in the graph. The sine wave will move from right to left as more data is acquired for the pressure channel. To display the entire sine wave, we need to change the Y axis scaling.
2 Guided Tour
41
5. Double click on the left axis of the graph. Unlike other components, you can double click on different areas of the graph to open the properties window for the graph to different pages. Double clicking on the left axis brings up the axis page with the left axis selected. 6. Next to Scale From enter -1, next to Scale To enter 1, then click OK. This will scale the graph from -1 to 1 which will show the entire graph.
42
Now we'll try another method to scale the graph. 7. Open the graph properties box again and go to the Traces page. Change the Y Expression to Pressure * 10 and hit OK. Like the other screen components, the expressions in graphs can be calculations as well as simple channels. In this case, we are multiplying each of the values of Pressure's history by 10 and plotting them. Since our range is -1 to 1, the graph will only display part of the sine wave. 8. Deselect the graph by clicking on the page outside of the graph. The shaded rectangle should disappear. Next, right click on the graph and select AutoScale - Y Axis The graph component has two different right click popup menus. When selected, it displays the same popup menu as the rest of the components. When it is unselected, it displays a completely different popup for manipulating the special features of the graph. After autoscaling, you should see the graph properly scaled from -10 to 10. Notice the rectangle around the graph. The left and right sides are green, while the top and bottom are purple. The purple lines indicate that the Y axis of the graph is "frozen". A frozen axis ignores the scaling parameters set in the properties window (like we did in step 6 above) and uses the scaling from an autoscale, pan, or zoom.
2 Guided Tour
43
9. To "thaw" the frozen axis, right click on the graph and select Freeze/Thaw - Thaw Y Axis Once thawed, the graph will revert to the -1 to 1 scaling indicated in the properties box and the box surrounding the graph will be drawn entirely in green. 10. Double click on the bottom axis to open the properties to the axis page with the bottom axis selected. Next to Time Width:, enter 120 and hit OK. If the double click method does not work, you can always open the properties window for the graph using normal methods, select the Axes page and click on Bottom Axis. In a vs. time graph, the bottom axis does not have a fixed scale. It changes as new data comes in so that the new data always appears at the very right of the graph. The time width parameter determines how far back in time from the most recent data point is displayed. By changing it from the default 60 to 120 we have told the graph to plot the last 2 minutes of data. Once again, if you zoom, autoscale, or pan the graph along the x axis, it will freeze the x axis and the graph will no longer update with newly acquired values. You must then thaw the axis to have the graph display a marching trace as normal.
44
For more information on graphs and the many ways you can display your data in graph form, go to the chapter entitled Graphing and Trending.
5. Click on Page_0 to go to our first page. 6. Right-click and select Displays-Variable Value to create another variable value component. 7. Right click on the new component and select Properties... to open the properties window. 8. For the expression, enter Out[0]. Feel free to set the caption as well. Like before, this will simply display the most recent value of the out channel. 9. Click on Action tab. This tab exists on several different components including the static ones and works the same way with all of them. 10. From the Action drop down, select Set To. There are many different options for the Action described later in the manual. The Set To action will prompt
2 Guided Tour
45
the user for a new value when the component is clicked. 11. Next go to Action Channel: type Out. 12. Leave the Range blank and click OK. The range allows you to constrain the inputs to particular values. By leaving these properties blank, we are indicating that we do not want a range limitation. The page will now display your caption and 0 with a big red X through it. This indicates that out does not have a valid value yet. This is because we haven't set it to anything.
13. Click on the component. A new window will appear requesting a new value. Enter any number and hit OK. Out will now be set to the value you entered. The component will now display your new value without the big red X. The next steps will not work in DAQFactory Express because it doesn't include knobs. Consider upgrading to any of the paid versions of DAQFactory to get knobs and thirty some other controls, among other things. 14. To try a different control, right click somewhere else on the screen and select Sliders & Knobs - Knob. Right click on the new component and select Properties... to open the properties window. 15. Next to Set Channel, type Out. Leave the rest of the properties at their default values and click OK. The knob is now set to control the out channel. 16. Click on the knob and drag in a circle as if turning the knob. You may have to click once beforehand to deselect the knob. The number inside will change indicating the present setting and out will be changed to this value. If you look at the variable value component we just created you will see it update as well. Likewise, if you click on the variable value component and set it to a different value (between the current knob's range of 0 to 100) you will see the knob update to the new setting.
46
You now know how to set an output to value using several different screen components. Next we will log the incoming data to disk.
For more information on the components that manually control outputs, see the chapter entitled Pages and Components. Most of the components can be used to control outputs. For more information on PID loop control see the chapter on PID loops. For more information on sequences and automating your system, see the chapter on Sequences.
2 Guided Tour
47
2. Click on the Add button in the logging set and when prompted for the new name, type in Log and click OK. Like channels and all other DAQFactory names, the logging set name must start with a letter and only contain letters, numbers or the underscore. Once you click OK, the logging set view will be displayed for the new logging set. You can also get to this view by clicking on the logging set name listed under LOGGING: in the workspace. You may have to click on the + sign next to LOGGING to see your logging sets listed in the workspace. 3. Next to Logging Method, select ASCII Delimited ASCII Delimited is probably the most common method for data logging as it can be read by most other programs such as Excel. Unfortunately, it is not as space efficient or fast as the binary methods. But unless you have strict space constraints or you are logging more than about 10,000 points per second (depending also on your computer / hard drive speed), we suggest ASCII since it can easily be read by other programs like Excel. 4. Next to File Name enter c:\DAQFactory\mylogfile.csv It is usually best to fully specify the path to your file, otherwise the data will be stored in your DAQFactory directory. The .csv is a windows standard designation for comma delimited values. Note the c: \DAQFactory directory will need to exist (and will if you installed DAQFactory in its normal place) 5. In the Channels Available table, click on the row with Pressure, then click on the >> button to move it to the Channels to Log table. Each logging set can log any combination of channels. In this case, we will just log the input channel. 6. Click on Apply to save the changes.
48
7. To start logging, click on the + next to LOGGING to display the new logging set, then right click on the logging set Log and select Begin Logging Set. Once started, the icon next to Log will change and the red stop sign will be removed to indicate that this logging set is running. 8. Wait at least 10 or 15 seconds to log some data and then right click on the logging set again and select End Logging Set to stop logging. There are other ways to start and stop logging sets, including the action page of some components such as the variable value component that we used earlier. 9. Now start Excel or Notepad and open the file c:\DAQFactory\mylogfile.csv. You will see two columns, time and data. By default the time is given in Excel / Access format which is decimal days since 1900. You can also have DAQFactory log in its standard format of seconds since 1970. If you are using Excel and logging the time in Excel format, you can format the first column as date / time and the numbers displayed will be properly displayed as date and time. Hint: if you cannot find the mylogfile.csv file, check to make sure that you selected Pressure to log and not Out. Since Out is an output channel, it only gets new values to log when you actually set it to something.
2 Guided Tour
49
This will popup a window that allows you to create a DAQConnect account and create or select a DAQConnect data source to send your data to. A data source is a collection of channels, typically from one location within your DAQConnect account. You can have multiple data sources within your account if you have multiple locations or you otherwise want to separate your data into groups.
2. Click on Create Account when the DAQConnect window opens, or if you already have a DAQConnect account, click Login, login and proceed to step 4. This will create a DAQConnect account, allowing you to send data to the web. There's a free plan so you can try it without providing a credit card or much of anything else. You will not need to login every time you start DAQFactory, just when you want to link a DAQFactory application to a DAQConnect data source. 3. Fill in the form with the appropriate details and click Create Account. When the Select Plan page appears, you can leave it on the free plan, or select a higher plan for more capabilities and click Continue. If you select a paid plan, you will be taken to the credit card page, otherwise you will go directly to the screen to create a new data source. 4. Enter Tank for your new data source name and click Create.
This will create a new data source named "Tank" and link it to your DAQFactory document. You can create other data sources in your account and switch among them by clicking on Real-time Web -> Connect again. 5. The window will close. Select Real-time Web -> Settings. Then check Display Detailed Status in Command / Alert and click OK.
50
This will cause DAQConnect status messages to appear in the command / alert window. This setting is designed for debugging only, and is not saved with the document. If all is well, you should see DAQConnect status messages, probably saying "Sending: 0 tags to server" in the Command / Alert window located at the bottom of the DAQFactory window. Now that your DAQFactory document is connected to DAQConnect, we can have our Pressure channel send its data to DAQConnect. 6. Click on CHANNELS: in the workspace, find the Pressure channel, and check the box under the column labeled DAQConn?. Click Apply.
The pressure channel will immediately start sending its data to your DAQConnect data source. Now we can go to DAQConnect in a browser and view the data: 7. Open up your favorite browser and browse to www.daqconnect.com then click on customer login or my account if you are already logged in. Feel free to do this on a different computer. Login using the account you created in step 2 above. Although you can use pretty much any browser, we recommend Chrome because it has the fastest JavaScript implementation, then Firefox, and finally, IE, which unfortunately still falls way behind in its JavaScript performance. 8. Once logged in, you will be presented with the main DAQConnect editor and a blank page. Click on the Basics menu at the top. You then see your Tank data source listed with the Pressure channel (or tag as its called in DAQConnect) listed underneath. To the right of Pressure are three icons. Drag the first one onto the big white area (the page) outside the menu to view the current Pressure reading as a number.
2 Guided Tour
51
9. Try dragging the other two icons to the page to view a gauge and a trend graph of your data. There are a number of other controls available in the Visuals menu. See the DAQConnect help for more information. 10. Click on Save at the top right corner to save your new DAQConnect page. Now you can login from anywhere to view real time values! There are ways to create restricted, read-only members with separate login for the same account, as well as the ability to embed your dynamic DAQConnect pages inside other web pages. Please refer to the DAQConnect help for more information. That is the very basics of DAQConnect. Feel free to explore more with your free account, and refer to the DAQConnect help for more details. There is also more detail on using DAQFactory with DAQConnect and control capability in the DAQFactory help.
You have now acquired, displayed, logged your data and viewed it on the web from a browser.
For simpler applications, it is simply a matter of repeating most of these steps for additional channels. But even for simpler applications there are many adjustments available for fine tuning your application to work the way you want. These, along with many more walk-throughs and examples are provided in the appropriate sections of this manual. At this point we suggest playing with DAQFactory a bit, jumping to the appropriate sections of the manual for more detail on the areas of DAQFactory you may be interested in utilizing.
III
53
54
data. Note: Both Save and Save with History will save non-calculated V. channel data to disk. See V.Channels for more detail. Application: Save with History could be used when you have an experiment that spans several days, but does not run continuously over night. At the end of the day, you can Save with History and shut down the system, then the next morning, load the document and start things back up again.
55
56
Enable DDE: DDE is a Windows mechanism for sharing data with another application running on your computer.
You could use DDE for example, to fill cells in an Excel spreadsheet in real time. Unfortunately, acting as a DDE server requires more processor power and overhead. Because of this, by default, DDE is disabled. To enable DDE for this document, check the enable DDE box. DDE is described in further detail in the networking chapter.
Disable Broadcast: Broadcasting refers to the mechanism DAQFactory uses to transfer data in real time to
other copies of DAQFactory running remotely. By checking this box, the internal network data server is disabled and no remote copies of DAQFactory can connect to this system. This is checked by default, so to use DAQFactory Networking, you must specifically uncheck this box. You will then need to save your document and restart to have the change take effect. We strongly recommend setting both a Full Connection and Slim Connection password as described below. This ensures that the data encryption used for communication uses a key that is unique to your application. If the password is not specified, the communication is encrypted with the same key as everyone else who leaves their password blank. The only time this would be safe would be when the system is on a completely stand alone network. Application: This option is designed for users running both Acquire mode and DAQFactory mode copies of DAQFactory on a single computer. The DAQFactory mode document should have broadcasting disabled, otherwise it will interfere with the Acquire mode document. Application: You could also disable broadcasting to absolute ensure that no one could have access to your real time data. This is why it is disabled by default. Broadcasting and networking is discussed in the networking chapter.
Disable Reboot / Restart: if you have broadcasting enabled and are connected over the Full data stream,
you can remotely reboot or shutdown the remote system. This is useful in headless applications. Since these applications are rare, this is checked (i.e. disabled) by default. To enable this feature you will need to uncheck this box, save your document then restart.
Load in Full Screen: Checking this will cause this document to load in full screen mode instead of the standard
mode with a window frame, menus, etc. You can manually switch between full screen and non full screen by clicking View - Full Screen from the main menu.
Load in Safe Mode: By checking this box, you can force this document to always open in safe mode. You can
2011 AzeoTech, Inc.
57
then start the acquisition and automation by selecting File-Leave Safe Mode, or use a system function. This allows you to create an application where an experiment might be started and stopped. See Safe mode for more info on this application.
Load in Acquire Mode: Acquire mode is described in the chapter entitled Other Features. Checking this box
causes DAQFactory to switch to Acquire mode automatically when the document is loaded. Note that Open in Safe Mode will ignore this setting and will not switch to Acquire mode.
Channel Persist Path: This allows you to change the directory where the channel persist files are stored. If
you are only working on one document, then you probably don't need to change this. If, however, you are working with multiple documents with the possibility of the same channel names amongst them, you will probably want to set each document with its own persist path so they don't conflict.
Auto Persistence Timer: Checking this box causes DAQFactory to perform a 'Save with History'
automatically in the background at the interval specified (in seconds). This feature has been depreciated. We strongly recommend using channel persistence instead. If the computer power is lost in the middle of doing the save with this method, your document could be corrupted. Application: The auto persistence timer is designed for users where power outages are common and they want to avoid having their graphs clear out every time the computer resets. Channel persistence achieves the same thing with more flexibility and more robustly.
Runtime Window Size: The runtime version of DAQFactory does not have a menu, toolbar, workspace or
other docking windows. It only has the page view. When the runtime engine loads this document, it will automatically size its window to the size given here in pixels. This keeps the runtime window from having a huge amount of white space when displayed on larger monitors.
Passwords: There are three different passwords available. Each one is set by entering the current password
(which defaults to blank) and then entering the new password twice. If you do not enter anything in these boxes, the password setting remains the same. Note that these passwords are not encrypted and are designed only as a deterrent. In cases where security is of grave concern, other methods should be employed. If you do not wish to require a password for a given event, set the password to blank.
Document Editing password: If specified, this password is required to open the document in any version
of DAQFactory except in runtime mode. Application: The document editing password allows you to create a document that you can distribute to anyone for use, but that cannot be edited even if they purchase a development copy of DAQFactory.
Full / Slim Connection: These passwords are required by a remote copy of DAQFactory to connect to the full
or slim data stream of this document. See Networking for more information. Application: If you do not want anyone to have access to your system remotely, but you still wish to have access, provide a password for both the slim and full stream. You can use the same password if you would like. Application: If you want to share some data with other users, but keep them from seeing all the data and making changes to channels, sequences and the like, put a password on the full connection, but leave the slim connection open, or better yet, make your slim connection password something simple and tell everyone it. This at least causes the data encryption to be unique to your application and protect it from hackers.
4 Expressions
IV
4 Expressions
59
4 Expressions
4.1 Expressions Overview
One of the powerful features of DAQFactory is expressions. Expressions are calculations that you can use in various places throughout DAQFactory, just about any place you need a number and many places you need a string. Expressions can be as simple as a constant or as complex as you need, acting on single data points or arrays of points. When entering expressions, DAQFactory provides syntax coloring and an intelligent drop down box that displays channels, formulas and other things you may want to use in your expression so you do not have to remember everything. Any edit box within DAQFactory that displays in color and some that do not can take an expression. Expressions are used to display calculated values, to graph calculations, to set ranges, to control data logging, and in many other locations.
60
The Command / Alert serves two purposes. It displays DAQFactory messages known as alerts, and it allows you to enter commands and expressions. The use of the command line interface is not required to use DAQFactory, but can be useful. If you cannot see the Command / Alert window, go to View - Command/Alert in the main menu. Most of this docking window contains a read-only area that displays DAQFactory alerts (in orange and red), commands you have typed in (in blue) and the results of those commands if any (in black or blue depending on whether it is a number or string). At the bottom is a single line editing area where you can type in commands. Commands can be any sequence script command that runs in one line. For example: global y = 4 read(MyChannel) Execute(strMyFunc) It cannot be script flow functions like while or for. When you hit Enter, the command is executed and added at the bottom of the display area. None of these commands will display anything else unless there is an error, in which case it will be displayed below the command. If instead of a command, you wish to see the result of an expression or function call, you can use the print command, denoted by the question mark. The print command can also be used in sequence script as described later. By putting a question mark first, the result of the expression after the question mark is displayed. This means what is after the question mark must be an expression and not a command. So, you can do: ? MyFunction() ? 5 + 3 etc. but you cannot do: ? global y = 4 ? read(MyChannel) etc. A few points: 1) you can use the up and down arrow keys to scroll through a history of the last 100 commands you've executed. 2) if you are debugging a sequence, the command line interface runs in the scope of the sequence being debugged to allow you to view private variables. The watch works the same way. As a bonus, though, you can actually change privates from the command line interface when a sequence is being debugged. The watch only allows you to view values. 3) when you print a large array, the entire array is actually displayed in the display area. So: ? MyChannel will actually display the entire history of MyChannel (at least the part in memory, see Persistence for more detail on that...) up to 10,000 values in each dimension. With variable value components, the watch, and big expression window only the first 20 values in each dimension are displayed. This is actually done so you don't hang your computer trying to print a million points of history every 1/2 second as the watch refreshes. 4) you can use the F2 key to quickly put your cursor in the command line from most views, even if the command/ alert window is hidden.
4 Expressions
61
the box and display a big expression window. To display the expanded expression window, either right click on the normal small expression edit box and select Expand Edit Box or hit F6 while editing the expression.
The expanded expression window contains two parts. The top is a large expression edit box. Here you should have plenty of room to enter the most complex of expressions. Feel free to hit the Enter key to split your expression into multiple lines. The linefeeds do not affect the expression. The bottom part of the window displays the result of the expression you've entered so far. This is especially handy when you are learning the syntax of expressions as it will give you immediate feedback as to the result of your expression. When you are done with the big expression window, hit the OK button to save your changes, or Cancel to forget them. Saved changes are inserted back into the small expression edit box. Note: For efficiency and responsiveness reasons, expressions that result in an array with more than 20 values will only display the first 20 values in the results area.
4.5 Arrays
All the data in DAQFactory is stored in memory in the form of arrays. DAQFactory supports scalars (0 dimension arrays), 1 dimensional arrays, 2 dimensional arrays, and 3 dimensional arrays. Because most of the data DAQFactory will see has a time associated with it, the arrays in DAQFactory have the ability to have a time associated with it. The time is automatically kept with the data making the data easier to manage. Non-time associated data is stored in simple arrays. This type of data is created in DAQFactory from the results of data analysis, calculations, or manually. A manual scalar is simply a number and is entered as such anywhere in the program. A 1 dimensional array can be entered in any expression using {} notation. For example {1,2,3,4} will make a 4 element array containing the numbers 1, 2, 3, and 4. Only numbers and commas are allowed between the {}, but these numbers can be in hex or binary format using the appropriate delimiter described a little later. To create a 2 dimensional array, you must nest the {} notation. For example, {{1,2},{3,4}} creates a 2x2 array. {1,2} are in one row, two columns, and {3,4} are in the second row, in two columns. Three dimensional arrays follow accordingly: {{{1,2},{3,4}},{{5,6},{7,8}}} This is a 2x2x2 array. Most of the data in DAQFactory has time associated with it. This is true for fresh data coming in and is stored in a channel. The array in a channel is called a history. A singular value read from your data acquisition device such as an A to D or Counter reading is appended along with its associated time to the 1 dimension array of values and times associated with that channel called the history. The new values are always inserted at the front of the array (giving the most recent value an index of zero). If the array grows larger than the given history length, the oldest values are removed. And so DAQFactory maintains a list of the most recent values of any given channel. With this list you can do any sort of data processing you may wish! For spectral data, which comes into DAQFactory as an 1 dimensional array of values with a single time stamp, data is appended to a 2 dimensional array, much like the
62
history of singular values. A single row of a 2 dimensional array corresponds to a spectra. Likewise, Image data, which is 2 dimensional with a single time, is appended to a 3 dimensional array, the 3rd dimension being time. A single image takes one row of the 3 dimensional array. Within DAQFactory, time always exists along the rows or first indexed dimension. Example: Lets assume we are reading a channel once a second. After the first read the channel would have something like: [0] Time 3:02:10 Data: 1.293
This is a scalar value with time. A second later it will have: [0] [1] Time 3:02:11 Time 3:02:10 Data: 1.382 Data: 1.293
This is an one dimensional array with two rows. And in one more second: [0] [1] [2] Time 3:02:12 Time 3:02:11 Time 3:02:10 Data: 1.483 Data: 1.382 Data: 1.293
Note: When doing array math, if you try and perform an operation or function on two arrays of different size when arrays of the same size are required, the longer array is truncated to the size of the shorter array before the operation is performed. If you perform an operation between an array and a scalar value, the operator will be applied to all the elements of the array. For example, the expression: {5,3,2} * 2 will return: {10,6,4}, but {5,3,2} * {2,3}, will return {10,9}. Note: Many properties that use expressions require a one dimensional value. If the result of the expression is an array, then the array is converted to a single dimensional value. If the array is one dimensional, then the most recent value is used. If the array is two or three dimensional, then the mean of the most recent row is used. It is recommended, however, that you explicitly perform this conversion in your expression using subsetting to avoid confusion.
4.6 Subsetting
If you specify a channel name in an expression, the entire channel history array will be returned. In some cases this may be exactly what you want, especially in graphs. In some cases, you will just want the most recent data point or some subset of your data. To get a subset of your data, put the desired range of points in brackets after the channel name. For example, ChannelName[0,4] will return the last five data points. You can get a single point as well: ChannelName[0] will return the most recent data point. Subsetting can actually occur at any point, for example: Sin(chan * otherchan[0])[0,49] will return the first 50 data points of the sine of the entire history of chan multiplied by the most recent value of otherchan. NOTE: A common error is to use () instead of [] for subsetting. Although this works in some cases, it does not work in all, nor do we guarantee that it will continue to work in newer versions. NOTE: Whenever possible, put the subset notation immediately after the channel or variable name. This allows DAQFactory to optimize the data retrieval. Otherwise, DAQFactory is forced to copy the entire channel history or variable array before subsetting. So, while you could do Sin(chan * otherchan[0])[0,49] it is much better to do sin (chan[0,49] * otherchan[0]). There are of course cases where you can't do this, which is why DAQFactory supports subsetting pretty much anywhere. Subsetting immediately after the channel name is especially important when channel persistence is used.
Advanced Subsetting
Some advanced subsetting is possible. For example you can specify time ranges in your subsetting, and instead of using the data point number, DAQFactory will use the times of your data points to determine which points get 2011 AzeoTech, Inc.
4 Expressions
63
returned. chan[5h,6h] will return all the values between 5 and 6 o'clock today. Of course this only works if the array has time associated with it, so ({1,2,3})[5h,6h] won't work, though ({1,2,3})[0,1] will return {1,2} For even more advanced subsetting, you can put calculations in your subsets. channel[Abs(otherchannel[0])]. There are many creative uses for this feature. For two and three dimensional arrays you can subset on multiple dimensions by repeating the [] notation. channel[3][2][1] returns the data point in the 4th row, 3rd column, 2nd depth. By not specifying a dimension, the entire dimension is returned. For example, given channel is 3 dimensional: channel[3][2] returns a 1 dimensional array of data points corresponding to the 4th row, 3rd column. channel[][2][1] returns a 1 dimensional array of data points corresponding to the 3rd column, 2nd depth. You can also specify ranges: channel[0,2][4][2] returns 3 values on the first three rows, 5th column, 3rd depth. The first specifier is always rows. Rows always corresponds to time, and therefore you can only subset in time along rows. So, channel[0][5h][2] is not valid, but channel[5h][2][4] is.
4.7 Strings
The DAQFactory expression parser can also handle strings. This can be used to parse or calculate the string I/O types, or for other uses. String channels and variables are used just like regular channels and support subsetting and other expression features. You have to remember that the value is a string however, and must be converted before using math functions. For example: "89" * 3 is invalid, but StrToDouble("89") * 3 is valid. String constants can be entered by enclosing the desired string in quotes (single or double quotes). String constant arrays are created just like numeric arrays: {"string a","string b"}. You can concatenate two strings using the add operator to make one string: "string a" + "string b". There are many other functions available for string processing. Please see the section on String Functions for the complete list. Note: While DAQFactory supports the storage of two and three dimensional string arrays, most of the DAQFactory functions do not work with string arrays with more than one dimension.
4 Expressions4.6 Subsetting
64
No date specified: 13h31m23.345 No year specified: 10m01d 13h31m23.345 No hour specified: 31m23.345 No minute or seconds specified: 13h this will actually give October 1,2001, 1:00:00.000pm No seconds specified: 13h31m this will give October 1,2001 1:31:00.000pm Just seconds specified: 365s this will give October 1,2001 1:06:05.000pm. Note that the s is required here, otherwise DAQFactory will just think you mean the number 365.
4 Expressions
65
Device.LabJack.AddRequest(...) Device.LabJack.GoOne(1) Device.LabJack.GetResult(...) Device.LabJack.GetResult(...) you could do: using("device.labjack") AddRequest(...) AddRequest(...) GoOne(1) GetResult(...) GetResult(...) Once you call using() with a prefix like above, it is added to a list and kept in the list as long as the document remains loaded. You do not have to keep recalling this function and can simply put this in an auto-start sequence. You can call using() multiple times with different prefixes to bring other functions and variables into the global namespace. Just be careful as there may be collisions with existing function and variable names.
66
+ * / % ^ ! ~ ~~ ~~~ any function ( This means that 1 + 2 * 3 equals the same thing as 3 * 2 + 1. The meaning of these operators is described in the next few sections.
And, Or
<=, >= Less Than Equal, Greater Than Equal ==, != ! iif()
Equal (that's two equal signs), Not Equal
Not
Inline if
When evaluating Boolean, any non-zero value is considered true. Therefore !5 equals 0. Like the math operators, the Boolean operators can be applied to arrays, so {2,5,0,2} >= {1,6,3,1} will return {1,0,0,1}. It is recommended when combining Boolean operators to use parentheses liberally. For example: if ((MyChannel[0] > 3) && (MyOtherChannel[0] < 2)) This will ensure you get the expression you expect and also makes it easier to read. The inline if, or iif() function is a function, not an operator, but this seems an appropriate place to put it. The function takes three parameters. The first is an expression. If the expression evaluates to a non-zero value, the function returns the second parameter. Otherwise it returns the third parameter. So: iif(5 < 10, "less than", "greater than") will return "greater than" while iif(15 < 10, "less than", "greater than") will return "less than"
4 Expressions
67
+, -, *, /: %, ^ ()
Modulus, Power
Parenthesis
These functions work both on scalar values and arrays of values. Examples: 3 + 2 returns 5 {3,5} + 2 returns {5,7} 2 is added to both elements of the array
{3,5} + {2,1} returns {5,6} each element of the array is added to the matching element of the other {3,5,6} + {2,1} returns {5,6} 8 % 3 returns 2 2 ^ 4 returns 16 the longer array is truncated to the size of the shorter array before adding
2 is the remainder of 8/3. 2 raised to the 4th power is 16. 2 raised to the 0.5 power is the same as the square root of 2.
&, |, #
SetBit(x, #)
68
ClearBit(x, #)
When evaluating bitwise operators and functions, all non-integer values are rounded down. For some advanced bitwise conversion, please see the section on byte conversions. Examples: given using binary notation: 0b0100110 & 0b0101001 returns 0b0100000 0b0100110 | 0b0101001 returns 0b0101111 ~0b0100110 returns 0b11011001 Note how the input value is filled out to 8 bits before performing the NOT.
~~0b0100110 returns 0b11111111 11011001 Note how the input value is filled out to 16 bits before performing the NOT. 0b0100110 << 1 returns 0b1001100 0b0100110 >> 1 returns 0b0010011 TestBit(0b0100110, 2) returns 1 SetBit(0b0100110, 3) returns 0b0101110 ClearBit(0b0100110, 2) returns 0b0100010 The bitwise operators, but not the Test, Set, ClearBit functions, can be applied to arrays: {0b1010, 0b0111} << 2 returns {0b10100,0b1110}
Abs Absolute Value (x) Ceil First integer above the current value (round (x) up) Floo First integer below the current value (round r(x) down) Exp Exponential (x) Ln (x)
Natural Log
4 Expressions
69
Ln(3) returns 1.099 Note that you can pass arrays into these functions as well: Ceil({5.3,5,-1.3}) returns {6,5,-1}
Normal: Sin(x) Cos(x) Tan(x) Inverse: ASin(x) ACos(x) ATan(x) Hyperbolic: SinH(x)
4 Expressions4.12 Expression Operator / Function Reference4.12.5 Math functions
70
CosH(x) TanH(x)
X is assumed to be in Radians. To convert degrees to radians, just multiply by Pi()/180: Sin(30 * Pi()/180) returns 0.500 As with most functions, you can pass scalar or array values to any of these functions. Examples: Sin(1) returns 0.841 Sin({1,2}) returns {0.841,0.909}
Mean(Array) provides the mean of the given array along the rows dimension. Examples:
Mean({1,2,3}) returns 2 Mean({{1,2,3},{4,5,6}) returns {2.5,3.5,4.5}
Sum(Array) provides the sum of the given array along the rows dimension. Examples:
Sum({1,2,3}) returns 6 Sum({{1,2,3},{4,5,6}) returns {5,7,9}
Min(Array) provides the minimum value of the given array along the rows dimension. Examples:
Min({1,2,3}) returns 1 Min({{1,2,7},{4,5,6}) returns {1,2,6}
Max(Array) provides the maximum value of the given array along the rows dimension. Examples:
Max({1,2,3}) returns 2 Max({{1,7,3},{2,5,3}) returns {2,7,3}
Variance(Array) provides the variance of the given array along the rows dimension. Examples:
Variance({1,2,4}) returns 2.333 Variance({{1,2,4},{4,5,6}) returns {4.5,4.5,2}
StdDev(Array) provides the standard deviation of the given array along the rows dimension. Examples:
StdDev({1,2,4}) returns 1.528 StdDev({{1,2,4},{4,5,6}) returns {2.121,2.121,1.414} All of the above functions have equivalents for other array dimensions:
MeanCols() MeanDepth() MaxCols() MaxDepth() MinCols() MinDepth() SumCols() SumDepth() VarianceCols() VarianceDepth() StdDevCols() StdDevDepth()
4 Expressions
71
Examples: Mean({{1,2,3},{4,5,6}) returns {2.5,3.5,4.5} 2.5 is the mean of 1 and 4 3.5 is the mean of 2 and 5 4.5 is the mean of 3 and 6 MeanCols({{1,2,3},{4,5,6}) returns {2,5} 2 is the mean of 1, 2 and 3 5 is the mean of 4, 5 and 6
Boxcar(Value, Boxcar Size) BoxcarSD(Value, Boxcar Size) BoxcarMax(Value, Boxcar Size) BoxcarMin(Value, Boxcar Size) BoxcarSum(Value, Boxcar Size)
All do essentially the same thing. They take a subset of the data in Boxcar Size sized chunks from value starting at index 0, and apply the appropriate function: Boxcar returns the mean of each of these chunks, SD the standard dev, etc. The returned array has a size equal to the size of the original array divided by the boxcar size rounded up. If the array size of value is not a multiple of boxcar size, then the last boxcar will have less then boxcar size elements used in its calculation. Example: Boxcar({1,4,2,6,7},2) returns {2.5,4,7} 2.5 is the average of 1 and 4 4 is the average of 2 and 6 7 is the average of 7. For arrays with time, the result of the boxcar has the time of the last point in each car stored. For BoxcarMax and BoxcarMin the time of the point in each car that is the max or min is stored instead. This is very useful for plotting. For example, assuming the MyChannel contained {1,4,2,6,7} with time associated with each data point then: GetTime(BoxcarMin({1,4,2,6,7},2)) would return a three element array with the time of the 1, 2 and 7 data points.
72
3 is the average of 4 and 2. 4 is the average of 2 and 6. 6.5 is the average of 6 and 7. 7 is the average of 7.
Asc(Character):
Converts the given character into its ASCII value. If you pass a string, only the first character is converted. For example: Asc({ABC,"DEF"}) returns {65,68}
AscA(String):
Same as Asc, but works on a single string and returns the ASCII value for each character in that string in an array. Only works with the first string. For example: AscA({ABC,DEF}) returns {65,66,67}
Chr(Value):
Converts the given value into the ASCII representation of that value. For example: Chr({65,66,67}) returns {A,"B","C"}
ChrA(Array of Values):
Same as Chr, but takes an array of values and creates a single string out of them. For example: ChrA({65,66,67}) returns ABC
Compare(String1,String2):
Compares two strings, case sensitive. Returns 0 if they match, -1 if String1 is less than String2, +1 if String1 is greater than String2. In most cases, it is easier to use the ==, < and > operators. Examples of Compare(): Compare("abcdef","abcdef") returns 0 but Compare("abcdef","abCDef") returns 1.
CompareNoCase(String1,String2):
Compares two strings case insensitive. Returns 0 if they match, -1 if String1 is less than String2, +1 if String1 is greater than String2. For example: CompareNoCase("abcdef","abCDef") returns 1 but CompareNoCase("abcdef","bdfsef") returns -1
Delete(String,Index,# Chars):
Deletes x number of chars starting at index in string. For example: Delete("abcdef",3,2) returns "abcf"
4 Expressions
73
DoubleToStr(Value):
This converts the given number to a string with up to 15 sig figs (the max for a double precision floating point value). This is essentially the same as Format("%f",Value)
Evaluate(String):
Evaluates the string as if it was an expression. Returns a value. For example: Evaluate("1+1") returns 2.
FindOneOf(String,Chars to find):
Finds the first instance of one of the given chars. -1 if not found. Returns an index. For example: FindOneOf("abcdef","ce",0) returns 2.
Format(FormatString,Value,[Value2],...):
Performs a standard C printf style format. You can have up to 19 values in a single call. To format a time value, see the FormatDateTime() function in the section on Time. The following types are supported (case sensitive): c or C: single byte character d or i: signed decimal integer o : unsigned octal integer u : unsigned decimal integer x : unsigned hexadecimal integer, using lowercase "abcdef" X : unsigned hexadecimal integer, using uppercase "ABCDEF" e : signed floating point value using exponential notation with a lower case "e" E : same as e but with an upper case "E" f : signed floating point value without exponent. g : signed floating point value with optional exponent depending on size of resultant string. In other words, 3.0 would be simply 3, but 3 million would be 3e+006
74
G : same as g but with an upper case "E" for the exponent. s or S : a string For the details of using the flags, width and precision arguments in printf, we refer you to any C programming text. For example: Format("My Value: %.3f",MyChannel[0]) returns "My Value 34392.492" You can also use several \ modifiers to generate special characters: \n : new line character, a line feed, ASCII 10 \r : return character, a carriage return, ASCII 13 \t : tab character, ASCII 9 \yyy: the ASCII character with the given code. All three digits are required. So, \065 will generate an A. \xzz: same as above, but the code is given in hex. The x is required along with two hexadecimal digits. So, \x0a is the same as \n or ASCII 10. \\ : a backslash
GetLength(String):
Returns the length of the string. For example: GetLength("abcdef") returns 6
HideHidden(String)
Takes all non-printing characters (ASCII values less than 32 or greater than 126) and removes them from the string. For example: ShowHidden(abc + Chr(9) + def + Chr(13)) returns abcdef
Insert(String,Index,Insert String):
Inserts the given string into the other given string starting at index. For example: Insert("abcdef",3,"abc") returns "abcabcdef"
Left(String,# Chars):
Returns x number of characters starting from the left of the string. For example: Left("abcdef",4) returns "abcd"
LTrim(String), RTrim(String):
Trims leading or trailing spaces. For example: LTrim(" abcdef") returns "abcdef"
MakeLower(String):
Returns the string converted to all lowercase. For example: MakeLower("Abcdef") returns "abcdef"
MakeReverse(String):
Flips the string. For example:
4 Expressions
75
Reverse("abcdef")
returns "fedcba"
MakeUpper(String):
Returns the string converted to all uppercase. For example: MakeUpper("abcdef") returns "ABCDEF"
Mid(String,Start,# Chars):
Returns a subset from the center of the string. Start is zero indexed. For example: Mid("abcdef",2,3) returns "cde"
Parse(String,Index,Parse By):
Assumes String is a list of values separated by Parse By. Returns the given index item into this list. For example: Parse("this,is,a,test",2,",") returns "a". Note 0 indexing (as always) If you specify a negative Index, then parse will completely parse the String and return an array of the separated strings. For example: Parse("this,is,a,test",-1,",") returns {"this","is","a","test"} If you only need one element out of your delimited string, use the first, indexed method. If, however, you are going to work with all the elements, it is much faster to use the second method and work through the array then to repetitively call Parse() with incrementing indices.
Remove(String,Remove Char):
Removes all instances of char in string. Remove("abcdef","a") returns "bcdef" For example:
Replace(String,Old,New):
Replaces all instances of old with new within string. For example: Replace("abcabc","a","b") returns "bbcbbc"
ReverseFind(String,Char to find):
Just like find, but starts from the back. Returns an index (from the front). For example: ReverseFind("abcdef","cd") returns 2.
Right(String,# Chars):
Same as Left() but from the right. For Example: Right("abcdef",4) returns "cdef"
ShowHidden(String)
Takes all non-printing characters (ASCII values less than 32 or greater than 126) and displays their ASCII code with a backslash in front. For example: ShowHidden(abc + Chr(9) + def + Chr(13)) returns abc\009def\013
StrToDouble(String):
Converts a string into a double for use in standard math functions. Converts up to the first invalid character. Returns a value. If the first character is invalid, it will return NaN. For example: 4 Expressions4.12 Expression Operator / Function Reference4.12.9 String functions
76
StrToDouble("534.27") returns 534.27. StrToDouble("534sd27") returns 534. StrToDouble("sd27") returns NaN. You can also specify hex or binary values by proceeding the number with "0x" or "0b": StrToDouble("0xff") returns 255. Although the function is called StrToDouble, if you use the hex or binary notation an integer is returned. Also, as when entering hex and binary constants, only the values between 0 and 2^31 are supported. To convert date and time strings to DAQFactory times, use the StrToTime() function shown in the section on Time.
Supported operands:
= (same as compare and is case sensitive) + (concatenates the strings) > < >= <=
Marks the next character as special. Precede any special character that you would actually like to search for with this symbol. For example, to search for '^' you would put '\^'.
A match occurs only if the character following this symbol is found at the beginning of a line or input.
A match occurs only if the character following this symbol is found at the end of the input, or line.
Searches for the preceding character zero or more times. For this implementation you must define more than one character. If only one character is specified in the regular expression then no matches will be found. That means that /zo*/ matches z and zoo, but /z*/ will match nothing because only one character has been specified.
Searches for the preceding character either one time or not at all. It cannot be defined if only one character is specified in the regular expression.
4 Expressions
77
(pattern)
Matches the specified pattern and remembers each match via unique indexes for each match found. Only characters enclosed within parentheses will be considered patterns. The found substring can then be retrieved by using '\0'-'\9' in the regular expression, where '0'-'9' is the identifying index number of that particular pattern. For example: '(re).*\0s+ion' will match 'regular expression' because it first finds the pattern 're' and remembers the pattern with an index of 0. '.*' will then match 'gular exp' in 'regular expression'. Then we look for the same pattern again by inserting '\0' into the regular expresson, which matches the second occurrence of 're' in 'regular expression'. Finally, 's+ion' matches 'ssion'.
x|y
Matches either character 'x' or 'y'. You can combine more than two characters (e.g. 'x|y|z').
{n}
The preceding character must match exactly 'n' times (non-negative values only).
{n,}
The preceding character must match at least 'n' times (non-negative values only).
{n,m}
The preceding character must match at least 'n' times and at most 'm' times. (n,m - non-negative numbers only).
[xyz]
A character set. A match occurs if any one of the enclosed characters is found.
[^xyz]
A non-matching character set. A match occurs if any character that is not in the set is found.
\b
Matches a word boundary. A boundary occurs between two non-space characters. Also, the ascii format characters, Chr(10) through Chr(13) do not define a word boundary. For example, the expression "me" + chr(10) only has one word boundary which occurs between the "m" and the "e".
\B
Searches for a non-word boundary. The exact opposite of the previous symbol ("\b"). A match occurs for any boundary between space characters or between a non-space character and a space character. For example, the expression " me"+chr(10)+" " has three (3) non-word boundaries: between the first space and the "m"; between the "e" and the newline character; and between the newline character and the last space.
\d
\D
\f
\n
\r
\s
78
\S
\t
\v
\w
Matches any alphabetic character including underscores. [A-Z a-z 0-9 _].
\W
\num
Matches any characters defined as a pattern with a unique index between 0 and 9. A match occurs if the pattern identified by 'num' is found (see the pattern description for an example).
/n/
A match occurs if a character is located with an ascii code of 'n'. 'n' must be between 1 and 255. You'll typically just want to use Chr() in creating your regular expression instead: FindExpr(MyVar, "abc" + chr(0) + "def")
Byte(): converts the given number into a signed byte (8 bit) sized value.
To.Byte(253) returns -3
uByte(): converts the given number into an unsigned byte sized value. This is only marginally faster than just
doing % 256, but possibly a bit clearer. To.uByte(259) returns 3
Word(): converts the given number into a signed word (16 bit) value.
To.Word({{0,128}}) returns -32768
rWord(): converts the given number into a signed word value by reversing the bytes to Big Endian (most
significant byte first) 2011 AzeoTech, Inc.
4 Expressions
79
urWord(): converts the given number into a unsigned word value by reversing the bytes to Big Endian (most
significant byte first) To.urWord({{0,128}}) returns 128
Long(): converts the given number into a signed double word (32 bit) value.
To.Long({{0,128,0,128}}) returns -2147450880
uLong(): converts the given number into an unsigned double word value.
To.uLong({{0,128,0,128}}) returns 2147516416
rbLong(): converts the given number into a signed double word value by reversing the bytes in each word to Big
Endian (most significant byte first). The words are left as Little Endian (least significant word first). To.rbLong({{0,128,0,128}}) returns 8388736
urbLong(): converts the given number into a unsigned double word value by reversing the bytes in each word to
Big Endian (most significant byte first). The words are left as Little Endian (least significant word first). To.urbLong({{0,128,0,128}}) returns 8388736
rwLong(): converts the given number into a signed double word value by reversing the words to Big Endian
(most significant word first). Bytes in each word are left as Little Endian (least significant byte first). To.rwLong({{0,128,0,128}}) returns -2147450880
urwLong(): converts the given number into a unsigned double word value by reversing the words to Big Endian
(most significant word first). Bytes in each word are left as Little Endian (least significant byte first). To.urwLong({{0,128,0,128}}) returns 2147516416
Float(): converts the given number into a 32 bit floating point value (IEEE format).
To.Float({{3,4,66,69}}) returns 3104.251
rwFloat(): converts the given number into a 32 bit floating point value, reversing the words
To.rwFloat({{3,69,66,69}}) returns 2100.329
rbFloat(): converts the given number into a 32 bit floating point value, reversing the bytes Double(): converts the given number into a 64 bit floating point value (IEEE format).
To.Double({{3,69,66,69,3,4,28,65}}) returns 459008.818
Converting to bits:
In addition to the above To functions there is one additional function for converting an integer into its bit array:
Bit(): converts the given number to an array of bits. If you provide a single number to this function, it will return
a 32 element array of the bits that make up that number. If you provide an array of numbers, a 2 dimensional array is returned. In both cases, the 32 elements are in the second dimension, with the least significant bit first. So: To.Bit(3) returns {{1,1,0,0,0,0,0,0,....,0}} To.Bit({3,4}) returns {{1,1,0,0,0,0...},{0,0,1,0,0,0,0,....}}
80
The above results are truncated for clarity, but in fact there will be 32 columns in each result. The default is to convert to 32 bits. If you want less bits, specify it as the second parameter of the function: To.Bit({3,4},8) returns {{1,1,0,0,0,0,0,0},{0,0,1,0,0,0,0,0}} Either way, you can then access individual bits using standard subsetting: Private bitarray = To.Bit(MyChannel[0]) if (bitarray[0][4]) .. do something endif bitarray[0][6] = 1 // set a bit Out = From.Bit(bitarray) Notice that we have to subset in the second dimension, not the first, to get a particular bit. If you are only converting a single value and want to avoid this you could always use the Transpose function: Private bitarray = Transpose(To.Bit(MyChannel[0]),0) if (bitarray[4]) .. do something endif At the end of the first example, we set a single bit and then used the From.Bit() function described below to convert the bit array back into its numeric representation. Note that if you do this in the second example after transposing, you will need to transpose back before calling From.Bit().
Byte(): converts the given signed byte value into an unsigned byte format.
From.Byte(-3) returns 253
uByte(): converts the given unsigned byte value into an unsigned byte format. This actually does the exact same
thing as Byte() and is a pretty useless function, but we've provided it when you want clarity in your code. From.uByte(3) returns 3
Word(): converts the given signed word value into an array of unsigned bytes putting the least significant byte
first. From.Word(-32768) returns {{0,128}}
uWord(): converts the given unsigned signed word value into an array of unsigned bytes putting the least
significant byte first. From.uWord(32768) returns {{0,128}}
rWord(): converts the given signed word value into an array of unsigned bytes putting the most significant byte
first. From.rWord(128) returns {{0,128}}
urWord(): converts the given unsigned word value into an array of unsigned bytes putting the most significant
byte first.
4 Expressions
81
Long(): converts the given signed double word value into an array of unsigned bytes with the least significant
byte first. From.Long(-2147450880) returns {{0,128,0,128}}
uLong(): converts the given unsigned double word value into an array of unsigned bytes with the least significant
byte first. From.uLong(2147516413) returns {{0,128,0,128}}
rbLong(): converts the given signed double word value into an array of unsigned bytes with the bytes in each
word reversed from standard Little Endian format of From.Long(). From.rbLong(-2147450880) returns {{128,0,128,0}}
urbLong(): converts the given unsigned double word value into an array of unsigned bytes with the bytes in
each word reversed from standard Little Endian format of From.uLong(). From.urbLong(2147516413) returns {{128,0,128,0}}
rwLong(): converts the given signed double word value into an array of unsigned bytes with the words reversed
from standard Little Endian format of From.Long(). From.rwLong(-2147450880) returns {{0,128,0,128}}
urwLong(): converts the given signed double word value into an array of unsigned bytes with the words
reversed from standard Little Endian format of From.uLong(). From.urwLong(2147517413) returns {{0,128,0,128}}
Float(): converts the given IEEE floating point value into an array of unsigned bytes.
From.Float(3104.251) returns {{4,4,66,69}}
rwFloat(): converts the given floating point value into an array of unsigned bytes with the words reversed from
IEEE format. From.rwFloat(3104.251) returns {{66,69,4,4}}
rbFloat(): converts the given floating point value into an array of unsigned bytes with the bytes reversed from
IEEE format.
Double(): converts the given IEEE double precision (64 bit) floating point value into an array of unsigned bytes.
From.Double(459008.818) returns {{193,202,161,69,3,4,28,65}}
Bit(): converts the given array of bits to its numeric representation. Unlike To.Bit(), you do not have to provide all
32 bits. DAQFactory will assume any bits not provided are 0. The least significant bit is always first in the array. Here are some examples: From.Bit({{1,1,0,1}}) returns 11. Note how the array of bits is in the second dimension. From.Bit({1,1,0,1},{0,1,1,0}}) returns {11,6} In a more programmatic way:
82
Private bitarray bitarray[0][3] = HeaterOn bitarray[0][1] = ValveState bitarray[0][0] = SwitchState Out = From.Bit(bitarray) Notice that we have to subset in the second dimension, not the first, to set a particular bit. This is not required if you are only converting one value at a time, but you can convert a full matrix of bits to multiple values this way. Both these examples also show a trick when doing array creation. By setting the largest array element ([3]) first, we preallocate the array to that size, putting 0's in all the other elements. If we were to set the elements in order, [0], [1], then [3], internally DAQFactory would be forced to reallocate three times which is much slower, especially when the arrays get large. Comment: now you may wonder why the To and From functions take and return values in the second dimension. This is because the first dimension in DAQFactory always refers to values in time, and individual bytes or bits are all part of a single value at a single time. This becomes handy when you want to do something like plot the status of a certain bit of a channel over time. Lets say you want to plot bit 2: Y Expression: (To.Bit(MyChannel,3))[][2] Notice also in the above expression that we do ,3. This means that only up to the desired bit is converted saving memory. Of course the better way to retrieve a single bit is to use the TestBit function: Y Expression: TestBit(MyChannel,3) But if you wanted to sum the second and third bits for some reason...: Y Expression: SumCols(To.Bit(MyChannel,3)[][1,2]) That all said, if you only want to convert to a single value with a To function (other then bit), or From.Bit, you can specify an array in the first dimension. So, To.Word({{0,128}}) is the same as To.Word({0,128}). Of course, when you are dealing with time, you have to follow the convention just described.
FormatDate(time array)
This function converts a DAQFactory time value into a string representation of the date using your current windows locale setting. For example, with a US locale: FormatDate(04y2m18d) returns "02/18/04"
4 Expressions
83
This function converts a DAQFactory time value into a string representation using the format specifier provided to the function. The format specifier works a lot like the Format() function, but with different codes. Here are the codes: %a The abbreviated weekday name (Mon, Tue, etc) %A The full weekday name (Monday, Tuesday, etc) %b The abbreviated month name (Jan, Feb etc.) %B The full month name (January, February, etc.) %c Date and time representation using the Window's locale settings %d The day of month as decimal number (01 31) %H The hour in 24-hour format (00 23) %I The hour in 12-hour format (01 12) %j The day of year as decimal number (001 366) %m The month as decimal number (01 12) %M The minute as decimal number (00 59) %p The A.M./P.M. indicator for 12-hour clock as determined by the Window's locale settings %S The second as decimal number (00 59) %U The week of year as decimal number, with Sunday as first day of week (00 53) %w The weekday as decimal number (0 6; Sunday is 0) %W The week of year as decimal number, with Monday as first day of week (00 53) %x Date representation using the Window's current locale settings %X Time representation using the Window's current locale settings %y The year without century, as decimal number (00 99) %Y The year with century, as decimal number %z, %Z Either the time-zone name or time zone abbreviation, depending on registry settings; nothing if time zone is unknown %% Percent sign Examples: FormatDateTime(The current hour is: %H,12h45m) returns "The current hour is: 12" FormatDateTime("%c", SysTime()) returns something like "02/20/04 12:14:07" depending on the current time and your locale settings. FormatDateTime("%B %d, %Y",SysTime()) returns "February 20, 2004" for the above time.
FormatTime(time array)
This function converts a DAQFactory time value (seconds since 1970) into a string representation of the time using your current windows locale setting. For example: FormatTime(1h2m3) returns "01:02:03" on a system set to display 24hr time. 4 Expressions4.12 Expression Operator / Function Reference4.12.11 Time functions
84
GetTime(array):
Many of the values in DAQFactory have time arrays or values associated with them. Often these time values are used automatically, but sometimes you may wish to get the time array associated with a value array. The GetTime () function does just that. Alternatively with channels and variables, you can use .Time notation. So GetTime (MyChannel) is the same as MyChannel.Time. However, this does not work for the results of expressions, so (Max (MyChannel[0])).Time won't work, but GetTime(Max(MyChannel[0])) will. This is especially useful with the max/ min functions as DAQFactory will actually return the time of the maximum or minimum point using GetTime().
ShiftTime(Value, Offset):
Often there are different latencies in instrumentation which makes intercomparison difficult without the ShiftTime (Value, Offset) function. This function returns Value with the time associated with it shifted by Offset.
SortTime(array):
DAQFactory typically takes care of keeping your data points sorted by time. However, when you perform the Concat function with two arrays with time associated with them, the resulting array will have time out of order unless all the points in the second array have times later than those in the first array. Often times this doesn't matter, but there are many parts of DAQFactory that, for optimization reasons, expect their arrays to be sorted by time. Graphs are the prime example of this. The SortTime(array) will sort an array for you based on time. We didn't automatically sort the array after a concat because often times you don't need to sort and sorting tends to be a relatively slow process.
SysTime():
To get the current computer time use the SysTime() function. This returns the number of seconds since January 1st, 1970 (with decimal seconds).
4 Expressions
85
Note: DAQFactory uses the system clock only to retrieve the initial time. Once DAQFactory starts, it uses the high precision counter to determine the current time. In addition to providing much more precise time measurements, this also means that changes to the system clock will NOT affect the DAQFactory time. You have to restart DAQFactory after a change in the system clock.
IsEmpty(Array)
Returns 1 if the given array is empty (no values). This can be used to determine if a particular channel has a valid value, whether a variable has been initialized, or to look at the return value for functions. Note that "{}" does not generate an empty array. Use NULL instead.
NumCols(Array)
Returns the number of elements in the Column (2nd dimension) direction of the given array NumCols({1,2,3}) returns 1. NumCols({{1,2,3},{2,3,4}}) returns 3. NumCols({{{1,2,3},{2,3,4}},{{4,5,6},{4,5,6}}} returns 2.
NumDepth(Array)
Returns the number of elements in the Depth (3rd dimension) direction of the given array. NumDepth({1,2,3}) returns 1. NumDepth({{1,2,3},{2,3,4}}) returns 1.
86
NumDepth({{{1,2,3},{2,3,4}},{{4,5,6},{4,5,6}}} returns 3.
NumRows(Array)
Returns the number of elements in the Row (1st dimension) direction of the given array. NumRows({1,2,3}) returns 3. NumRows({{1,2,3},{2,3,4}}) returns 2. NumRows({{{1,2,3},{2,3,4}},{{4,5,6},{4,5,6}}} returns 2.
Point():
Point(Value) returns the index of each element in the rows direction in place of the value of the element. For example, Point({4,2,5,3,8}) will return {0,1,2,3,4}
Transpose(Array, Dimension)
Takes a one dimensional array and changes the direction to the given dimension. This only works on one dimensional arrays. For dimension, use 0 to create an array with multiple rows, 1 for multiple columns, and 2 for multiple depth. Transpose({1,2,3},1) returns {{1,2,3}}. This took an array with three rows, and returned an array with three columns.
4 Expressions
87
RandUniform(Bottom, Top, Array Size) returns an array of Array Size filled with random numbers
evenly distributed between Bottom and Top.
4.12.16 Constants
For your convenience, we have provided quite a few constants:
Pi()
3.141592653589793
88
Amu() MassN() MassE() MassP() ChargeE() BohrRadius() Planck() GConstant() GAcceleration() SpeedLight() Boltzmann() Rydberg()
1.660566e-27 kg
1.674954e-27 kg
1.672649e-27 kg
9.109534e-31 kg
1.602189e-19 C
5.29177e-11 m
6.626176e-34 Js
6.6720e-11 Nm2kg-2
9.80665 m/s2
2.9979246e8 m/s
1.38066e-23 J/K
1.0973732e7 1/m
6.022045e23 1/mol
8.31441 J/Kmol
9.64846e4 C/mol
8.854e-12 AsV-1m-1
4 Expressions
89
1.25664e-6 VsA-1m-1
0.577215664901532
1.618033988749894
Convolution and Correlation: Convolve(Value1, Value2) ConvolveFFT(Value1, Value2) Correlate(Value1, Value2) CorrelateFFT(Value1, Value2)
These functions perform convolution or correlation of Value1 and Value2. The FFT version simply uses an FFT to aid in the calculation.
FFT Functions:
All the FFT functions perform an FFT on the given array. The difference between them is how the resulting imaginary array is converted into real values:
FFTReal(Value)
FFTPower(Value) Performs a power function on the result of the FFT FFTModulus (Value)
Performs a modulus function on the result of the FFT
FFT Windows:
The following windows are available to be used before performing an FFT operation. Each simply returns the Value after the window has been applied.
90
BlackmanHarris4(Value) TriangleWindow(Value) CosineWindow(Value) PoissonWindow(Value, Alpha) Histogram: Histogram(Value, Bin Array): returns value binned into bins as determined by Bin Array. Bin Array holds
the upper limit of each bin. The resulting array is one element larger than Bin Array. All elements in Value above the last bin in Bin Array are put in this extra bin. Note that Bin Array must be in increasing numeric order to work properly.
Interpolation: InterpolatePoly(X Array, Y Array, Interpolate To Array X) InterpolateRational(X Array, Y Array, Interpolate To Array X)
Both of these functions interpolate the function described by X vs Y array to the X values given in Interpolate To Array X. The first function uses a polynomial function to perform the interpolation, the second, the rational function.
Answer:
As of 5.70 we've added a function called StrToTime() to do this. This function is described in the section on Time functions. Since the old method is useful as an example of parsing and evaluate(), we've left it here: There isn't a direct function, but there is a pretty easy way to do it using the Evaluate function. The general idea is that DAQFactory expressions will accept time and date as constants if specified using our YMD hms format. So, "2012-1999 13:15:02" (European format) would be "99Y12M20D 13H15M02" So, what we need to do is get your string into that format. To do this, we'll create a sequence function that takes two arguments: strArg0 = "20-12-1999" and strArg1 = "13:15:02": Private string strY = Parse(strArg0,2,"-") Private string strM = Parse(strArg0,1,"-") Private string strD = Parse(strArg0,0,"-") Private string strH = Parse(strArg1,0,":") Private string strMin = Parse(strArg1,1,":") Private string strS = Parse(strArg1,2,":") Private result = Evaluate(strY + "Y" + strM + "M" + strD + "D" + strH + "h" + strMin + "m" + strS) return (result) You could of course put all the Parse() statements in the evaluate and skip all the variables, but this is a bit easier to read. Now, you can call your function from anywhere. Lets say we called this sequence StringToDate. So: Var.date = StringToDate("20-12-1999","13:15:02") To confirm it is working, go to the command line and put:
4 Expressions
91
? FormatDateTime("%c",StringToDate("20-12-1999","13:15:02")) The FormatDateTime() will take the DAQFactory time you created in your sequence and convert it back to a string. They should therefore match.
Answer:
First you need to come up with a way to enter the time. You can use the date/time edit box but it returns the full date and we just want the time, but we can get around that using modulus. So you put those times in PeakTimeStart and PeakTimeStop. We'll assume that peak time is always in the middle of the day and never across midnight. OK, now that we have those values, you should put an event on your channel that determines the energy cost. Lets say the channel is called "Usage" and cost = usage * 10. Here's the event code: CurrentCost = Usage[0] * 10 switch case ((SysTime() % 86400) < (PeakTimeStart % 86400)) // non-peak if (OffPeakCost < CurrentCost) OffPeakCost = CurrentCost // this also sets the time too! endif case (((SysTime() % 86400) >= (PeakTimeStart % 86400)) && ((SysTime() % 86400) < 86400))) // peak if (PeakCost < CurrentCost) PeakCost = CurrentCost // this also sets the time too! endif case ((SysTime() % 86400) >= (PeakTimeStop % 86400)) // non-peak if (OffPeakCost < CurrentCost) OffPeakCost = CurrentCost // this also sets the time too! endif endcase A few quick points: 1) % is modulus, which in this case strips the date from DAQFactory time and simply returns the time of day in seconds since midnight. Since the date/time component returns the full date and time even if you only display the time in the component, we have to strip it for the comparison. 2) you could do this in a sequence with an infinite loop and a delay() instead of an event. By using an event, this always get called every time CurrentCost is calculated and you don't have a second loop running. 3) we used a switch/case statement here since only one of the three options can exist at a time. Using switch runs a little faster than a bunch of ifs. 4) the code could be made more efficient by pre-calcing the modulus: Private time = SysTime() % 86400 PeakTimeStart = PeakTimeStart % 86400 PeakTimeStop = PeakTimeStop % 86400
(PeakTimeStop %
92
and then use these variables in the case statements. 5) as the comments indicate, the time of the peak is also stored. When the first line executes, CurrentCost = Usage [0] * 10, the time of Usage[0] is stored with CurrentCost. When OffPeakCost = CurrentCost is executed, once again the time carries through. This means you can display both OffPeakCost and OffPeakCost.Time to display the peak cost and the time of that peak cost. 6) this code does not reset the Peak and OffPeak costs each day. You'd have to do this manually by setting the variables to 0. You can do this automatically with a flag. Lets assume you've initialized it somewhere else and called it PeakFlag: CurrentCost = Usage[0] * 10 Private time = SysTime() % 86400 PeakTimeStart = PeakTimeStart % 86400 PeakTimeStop = PeakTimeStop % 86400 switch case (time < PeakTimeStart) // non-peak if (PeakFlag) OffPeakCost = 0 PeakFlag = 0 endif if (OffPeakCost < CurrentCost) OffPeakCost = CurrentCost // this also sets the time too! endif case ((time >= PeakTimeStart) && (time < PeakTimeStop)) // peak if (!PeakFlag) PeakCost = 0 PeakFlag = 1 endif if (PeakCost < CurrentCost) PeakCost = CurrentCost // this also sets the time too! endif case (time >= PeakTimeStop) // non-peak if (PeakFlag) OffPeakCost = 0 PeakFlag = 0 endif if (OffPeakCost < CurrentCost) OffPeakCost = CurrentCost // this also sets the time too! endif endcase
Answer:
The trick to solving this involves some boolean math. Change your V channel expression to: Trane_kwRef * (TraneKWE != 0) / (TraneKWE + (TraneKWE == 0)) Here we have two boolean sections. The first, in the numerator, set the value to 0 when TraneKWE equals 0. This is
4 Expressions
93
because (TraneKWE != 0) evaluates to 0 when TraneKWE does equal 0, and 1 when it does not. The boolean in the denominator prevents a divide by 0 error by adding one to the denominator when TraneKWE equals 0. This is again because (TraneKWE == 0) evaluates to 0 or 1. Continuing on, let's say you wanted the value to read -999 instead of 0 when TraneKWE equals 0. The denominator will stay the same, but the numerator will be changed: (Trane_kwRef * (TraneKWE != 0) - 999 * (TraneKWE == 0)) / (TraneKWE + (TraneKWE == 0)) The trick here in the numerator is that only one of the two boolean expressions will be true at a time since they are opposites. So we'll either get: Trane_kwRef * 1 - 999 * 0 = Trane_kwRef or Trane_kwRef * 0 - 999 * 1 = -999 This numerator expression actually shows how to do an inline iff() statement that exists in many other languages. This structure and the iff() allows you to select one of two values for use in the rest of an expression based on a boolean expression similar to an if. iff() is not supported by DAQFactory. Using this method, though, you can actually extend it to multiple options: 1000 * (x > 10) + 500 * ((x <= 10) && (x > 0)) + 50 * (x <= 0) This will return 1000 if x is greater than 10, 500 if x is between 0 and 10, and 50 if it is less than 0. Notice how we cover every possible value of x using a combination of > and <=. This can of course be extended to more values. Note that all these expressions could be used anywhere, not just in a V channel. In many situations, however, you may want to use [0] notation on all the channels so you only get the most recent reading. By not using [0] here this creates a V channel with a full history based on the histories of Trane_kwRef and TraneKWE. Finally, and hopefully not to confuse you, any computer scientist will tell you that + and * can actually be thought of as OR and AND in these sort of situations. So: Trane_kwRef * (TraneKWE != 0) - 999 * (TraneKWE == 0) actually could be read as: Trane_kwRef AND (TraneKWe != 0) OR -999 AND (TraneKWE == 0) (remember the minus sign in the original expression is really just + -999 ...)
Question:
I've been using Auto Split Files to separate my logging files into hourly files, but there are two problems. First, the auto split goes on number of data points and not time, so if I miss a data read, the timing is off. Second, the files don't necessarily start and stop on the hour. How can I fix these problems?
Answer:
You can't use the automatic file splitting and should turn that off. Then create a new sequence that starts with your application. Assuming your logging set is named "MyLog" the sequence would look like this: while (1) // set the logging file name to "MyData" plus the date/time Logging.MyLog.strFileName = FormatDateTime("MyData_%y%m%d_%H%M.csv",SysTime()) // wait until next hour
4 Expressions4.13 Questions, Answers and Examples4.13.3 A trick to avoid divide by 0 and other boolean tricks
94
waituntil(floor(SysTime() / 3600) * 3600 + 3600) // and loop around and update the file name endwhile
Question:
DAQFactory is setup to measure every second. We made a logging file that logs every hour by putting the interval to 3600 on the channel. This is a very nice type of logging for us because we now get 24 logs/day an 365 *24 =8760 logs a year. (All the logs can be in one file) Is it possible to start the logging at the whole hour (for example 8.00 or 9.00 etc.), because now we get a logging from for instance 8.21 to 9.21 etc.
Answer:
There are two different solutions depending on whether you still want to take data every second and only log once an hour, or do you want to take and log data every hour on the hour? If you just want to take a reading every hour on the hour and record it, do this: while (1) // trigger the reads: read(MyChannel) read(MyOtherChannel) // wait until next hour waituntil(floor(SysTime() / 3600) * 3600 + 3600) // and loop around and read again endwhile This will read a data point when the sequence starts, and then on the hour after that. You'll need to set the Timing of the channels to 0. If you want to take data faster than once an hour, but log each hour you'll need to use an export set. In the export set, set your Expression to, for example, "MyChannel[0]" to just export the most recent reading. Then use this sequence to trigger the export set. You'll need to set the Timing of MyChannel to 1 or whatever read interval you'd like. You'll notice the sequence is very similar to the above sequence, as this format works for whatever you want to do on the hour: while (1) // trigger export beginExport(MyExport) // wait until next hour waituntil(floor(SysTime() / 3600) * 3600 + 3600) // and loop around and export again endwhile Also, using an export set in this way is a very easy way to log a single line of data when certain events occur.
Question:
OK, now how do I do it twice a day?
Answer:
Just change the waituntil(). Replace all the 3600's with 43200 which is the number of seconds in half a day. Of course this results in the event occurring at noon and midnight. To make it occur, say, at 6am and 6pm, is a bit trickier. You cannot simply do: waituntil(floor(SysTime() / 43200) * 43200 + 21600) As this will cause an infinite loop once 6am or 6pm hits (challenge: figure out why this would occur!). So you have to do two waits in a row: waituntil(floor(SysTime() / 43200) * 43200 + 43200) // wait until noon or midnight waituntil(floor(SysTime() / 43200) * 43200 + 21600) // wait until 6pm or 6am after noon or midnight Finally, to explain, doing:
4 Expressions
95
Floor(x/y) * y is the standard way of truncating to the factor of y. So, in our original hourly case, we are truncating out the minutes and seconds and getting the time of the last hour. By doing +3600 we are saying, wait until the next hour. You MUST add the same amount as you are dividing, i.e. Floor(x/y) * y + y or you will create an infinite loop and crash your application once the first time event occurs. You can add a different amount, Floor(x/y) * y + z where z < y, if you do Floor(x/y)*y + y immediately beforehand. To do things once a day, please see the example in the logging chapter. Likewise, an example of doing things once a month is also there.
Answer:
Yes. Let's say you are storing the 0's and 1's in a channel called "State" with a history of 3600. Var.Trans = (State[0,3600] != State[1,3600]) Var.TotalTrans = Sum(Trans) The first statement creates an array of 0 and 1, putting a 1 everywhere there is a transition from 0 to 1 or 1 to 0. The second then sums those 1's. Of course to get just transitions from 0 to 1, divide Var.TotalTrans by 2, or better yet: Var.Trans = ((State[0,3600] != State[1,3600]) && State[1,3600] Var.TotalTrans = Sum(Trans) Now the first line puts 1's where there is a transition and the second value in the transition is 1 (i.e. 0 to 1).
Answer:
There are two ways. The slow way is to use FormatDateTime() to format a string with just the minute and convert the result into a number. This is actually the best way to get the current day, month or year number. However, to calculate what hour, minute or second it currently is, you can use simple math because there are always 60 seconds in a minute, 3600 seconds in an hour and 86400 seconds in a day. Math is always faster then any string function, and FormatDateTime() is particularly slow. Current second: SysTime()%60 Current Minute: SysTime()%3600/60 Current Hour:
96
SysTime()%86400/3600 The above formulas will give you a value with decimals. If you want an integer, just use floor(): Floor(SysTime()%86400/3600)
98
Indentation Conventions:
To make sequences easier to read, we strongly recommend using indenting to organize your code. Block operations are typically indented three spaces to clearly display the block. For example: if (condition) do something and something else else
99
do something endif You can manually indent or outdent blocks of code by selecting the block and pressing tab or shift-tab.
Saving Changes:
To save the changes made to a sequence, click the Apply button. Alternatively, if you want to check for possible syntax errors, you can click Apply & Compile and the sequence will be saved and compiled. If you do not compile, the sequence will automatically be compiled when you try and run it. Note: If you apply changes to a sequence that is running, you must stop and restart the sequence before the changes will take effect. Likewise, if you apply changes to a sequence that is called from another running sequence or expression, the changes will not apply until the sequence has returned. To quickly save your sequence, compile it and run it (or restart it if it is already running), select Debug - Start Sequence. Note that this menu item will change depending on whether the sequence is compiled and whether it is already running. You can also use F5 to do the same thing.
100
Note that you can only have one window open for a particular sequence.
101
The first line sets MyOutputChannel to its current value plus 1. The second, sets X to its current value minus 1. These are the same as: MyOutputChannel = MyOutputChannel[0] + 1 X = X + 1 If you need to increment or decrement by larger amounts, you can use the following notation: MyOutputChannel+=2 This will set MyOutputChannel to its current value plus 2 and is the same as: MyOutputChannel = MyOutputChannel[0] + 2 This notation can be used for more advanced assignment as well: MyOutputChannel+= InputChannel[0] / 2 This will set MyOutputChannel to its current value plus the latest value of InputChannel[0] divided by 2. This is the same as: MyOutputChannel = MyOutputChannel[0] + InputChannel[0] / 2 There are equivalent operators for subtraction, multiplication, and division: X -= 3 Y *= InputChannel[0] Z /= 10 which is the same as: X = X - 3 Y = Y * InputChannel[0] Z = Z / 10
ArrayStep()
The arraystep statement also does assignment, but works a little differently. It is best explained with an example: while(1) arraystep(Out,{1,3,4}) delay(1) endwhile This example will set the Out channel to 1, wait one second, then set Out to 3, wait another second, set Out to 4, wait another second and then repeat. The format of the arraystep statement is: arraystep(channel/variable, array). The array can be fixed, like the example, or an array from a channel or expression.
5.6 Reading inputs with the read statement and process control loops
For many applications, data is acquired from devices at constant intervals. These are the applications that the Timing parameter of a channel is designed for. For some applications you may want to read data at varying intervals and Timing will work for that as well. Some applications you will only want to read data when you need it. For these types of applications there is the read() statement. In order to use the read statement though you must still create a channel to identify what input you wish to read. Since you are using the read() statement for acquiring the data you should set the Timing parameter for your channel to 0. Now, assuming we've created a channel called Input with a Timing of 0, we can use something like the following to read the channel at a varying time interval: while(1)
5 Sequences & Scripting5.5 More advanced assignment operators and the arraystep statement
102
read(Input) delay(readinterval) endwhile This sequence will read Input at an interval determined by readinterval. readinterval could then be set using a page component allowing the user to specify the acquisition rate without changing the channel parameters. Another use for the read statement is for process control loops. One way to implement process control loops is to read your inputs at fixed rate using the Timing parameter and use the channel's event. The event sequence code is executed every time a new value arrives on the channel, so you can evaluate the input and perform an output based on that input value. Alternatively, you can combine the polling and the control into a single loop. For example: while(1) read(Pressure) if (Pressure[0] > 50) // if pressure is too high VacuumPump = 1 // start pump while(Pressure[0] > 50) // wait until pressure drops delay(1) read(Pressure) // read pressure again to check current value endwhile VacuumPump = 0 // then stop pump endif read(Temperature) if (Temperature[0] < 30) // if temperature too low Heater = 1 // turn on heater while (Temperature[0] < 30) // wait until warmer delay(1) read(Temperature) endwhile Heater = 0 // turn off heater endif delay(1) endwhile Although a simple example, it is pretty straight forward when things occur relative to each other. The pressure is read in from the device, then it is checked, then the temperature is read, then it is checked, then we wait a second and repeat. We could continue this and make a more complex control system. When doing process control, and many other sequence tasks it is usually much easier to split things into separate sequences. In our example above, we are monitoring temperature and pressure. If the pressure gets too high, we turn the pump on until it drops. If the temperature is too low, we turn on the heater until it warms up. The problem here is two fold. First, if both the temperature drops and the pressure rises at the same time, the system will have to pump down the system until the pressure drops below 50 before it can start heating the system up. This may be desired, but if not, this is not the fastest way to get the system under limits. Second, this makes for a more complicated sequence. Instead we can make two sequences: Sequence MonitorPressure: while(1) read(Pressure) if (Pressure[0] > 50) // if pressure is too high VacuumPump = 1 // start pump while(Pressure[0] > 50) // wait until pressure drops delay(1) read(Pressure) // read pressure again to check current value endwhile VacuumPump = 0 // then stop pump endif delay(1) endwhile Sequence MonitorTemperature: while(1) read(Temperature) if (Temperature[0] < 30) // if temperature too low Heater = 1 // turn on heater while (Temperature[0] < 30) // wait until warmer delay(1) read(Temperature)
103
endwhile Heater = 0 // turn off heater endif delay(1) endwhile These two sequence can run concurrently within DAQFactory and so both temperature and pressure can be monitored and adjusted simultaneously. If the pressure rises too high and the temperature drops at the same time, the system can heat and pump down at the same time, being monitored by two separate sequences. In general, you would probably stick with channel events for simple control like this. To see why, here is the event code for Pressure, assuming you had a Timing of 1 on the Pressure channel to poll it. The code to control the temperature would be very similar: if (Pressure[0] > 50) VacuumPump = 1 else VacuumPump = 0 endif or even more succinctly: VacuumPump = (Pressure[0] > 50) or for hysteresis, which is not implemented in any of the above code: if (Pressure[0] > 50) VacuumPump = 1 endif if (Pressure[0] < 40) VacuumPump = 0 endif
beginpid / endpid: These two statements will start or stop a PID loop. PID loops also run in separate threads
inside of DAQFactory and therefore run concurrently with sequences. These statements will return immediately. beginpid(MyPIDLoop)
5 Sequences & Scripting5.6 Reading inputs with the read statement and process control loops
104
beginlogging / endlogging: These two statements will start or stop a logging set. Like PID loops and most
sequences, logging sets run in their own thread concurently with sequences and PID loops. These statements will return immediately. Note that logging sets have a little time latency built in so additional data may be logged after the logging set is complete. Logging sets are really designed to be left running. If you want to conditionally log data, use an export set instead to log a single line of data, and then trigger the export set every time you want to log a line of data. beginlogging(MyLoggingSet)
beginexport / endexport: These two statements will start or stop an export set. Like PID loops and most
sequences, export sets run in their own thread concurrently with sequences and PID loops. These statements will return immediately. beginexport(MyExportSet)
105
time 5m OutputChannel = 0 OtherOut = 0 time 1h1m1 goto (0) This sequences also shows time being specified using hms format. This allows you to specify times in minutes or hours or a combination. Note that these are relative times not absolute times and the date is not used. This sequence also shows the block if statement correctly used at a single time. If you are going to put block statements like if in a sequence using time, make sure you do not have a time statement inside the block. NO: time 0 if (Input[0] > 2) time 1 OtherOut = 1 endif time 2 goto (0) The goto statement can go to other times besides 0 too: time 0 OutputChannel = 1 time 5 OtherOut = 1 time 10 OtherOut = 0 time 15 goto (5) This sequence will initialize OutputChannel to 1, wait 5 seconds, then alternate OtherOut between 0 and 1 every 5 seconds. As you can see the time / goto type sequence makes things pretty easy for creating timed loops. It is important to remember though that for more complicated loops that may branch in different ways or require different delays, this method is not the best. A while loop and wait or delay statements are definitely the preferred method for anything other than the most basic timed loops. Note: The time statements are non-propagating and therefore work like a wait() function. This is no problem if the things you are doing between the time statements will always take less time then the difference: time 0 read(MyChannel) time 1 goto 0 In the above example, as long as reading MyChannel will always take less than 1 second, then there will be no problem. This is usually the case for PCI DAQ cards and some external devices, such as the LabJack USB devices. If, however, it is possible for it to take longer than one second then this can cause a backlog and hang DAQFactory. The most common case where this occurs is when MyChannel refers to a serial channel, the timeout is set to one second or more, and the serial device is timing out. Sequences do not generate Timing Lag errors and do not reset their queue. So, if your device timed out for 60 seconds and then began functioning again, there would be 60 reads queue up and overdue. These would execute in rapid succession temporarily hanging DAQFactory.
106
107
there was no waiting. If this was inside a loop, the loop would run without any pausing to allow DAQFactory to do other things which could hang DAQFactory. To wait a half second between setting Output, the delay statement is the correct choice: Output = 1 // this occurs as soon as the sequence starts delay(0.5) Output = 0 // this occurs 1.5 second after the sequence starts delay(0.5) Output = 2 // this occurs 3 seconds after the sequence starts
waituntil()
The waituntil command will wait until an absolute time: Output = 1 waituntil(16h) Output = 2 The above sequence will set Output to 1, then wait until 4pm today and set Output to 2. If it is already past 4pm, the sequence will set Output to 1 then immediately set Output to 2. Application: Repeating something at the same time every day: The most common use of waituntil() is to repeat something at the same time every hour, day or week. Here's an example that uses waituntil() to repeat something every day: while (1) WaitUntil(16h + 86400) do something... endwhile Each time 16h is evaluated, it will automatically add in today's date, whatever that may be when the waituntil() line is executed. Depending on when the sequence started, it may already be past 4pm and we don't want the "do something" to execute until tomorrow. So we simply add 86400 to 4pm today which gives us 4pm tomorrow because there are 86400 seconds in a day. Thus the "do something" will execute at 4pm every day starting tomorrow at 4pm. If you want the "do something" to start at 4pm today if sequence is started before 4pm, then you have to add some steps: if (SysTime() < 16h) // if its not 4pm yet WaitUntil(16h) // wait until 4pm else WaitUntil(16h+86400) // otherwise, wait until 4pm tomorrow endif while (1) do something... WaitUntil(16h + 86400) // wait until 4pm tomorrow. endwhile By reorganizing the loop to do something first, then wait until 4pm tomorrow we can add an if statement in front of the loop to determine when we want "do something" to execute first. If its not 4pm yet, then we simply wait until 4pm today, otherwise we wait until 4pm tomorrow. A key to these samples is that while today's date is added to 16h each time the steps with 16h are executed, it only does so once. So while waiting for 4pm tomorrow (16h + 86400), the 4pm is not reevaluated at midnight thus pushing it back to 4pm the next day, and the next, forever in the future.
waitfor()
waitfor() is a bit different than the other wait statements. waitfor() will wait for a particular expression to evaluate to true: output = 1 waitfor(Input[0] > 10,1)
108
output = 2 This sequence sets output to 1, then waits for Input to go above 10, then when that occurs sets output to 2. This of course assumes that you are reading Input somewhere else, either by setting the Timing parameter in the Input channel, or reading the channel through another sequence. The second parameter of the WaitFor statement determines how often the expression is evaluated. In this case, "Input[0] > 10" is evaluated once a second. To conserve processor power, this value should be set as high as possible. There is no practical use for setting it smaller then the rate the values in the expression are being updated, and it should never be smaller than 0.01 unless you have a multiprocessor computer and have planned for it. In general it should be set to maximum acceptable delay between the time the expression would evaluate to true and the time the next statement needs to execute. So in our example, if it is acceptable for Output to be set to 2 up to five seconds after Input goes above 10, then we should do "waitfor(Input[0] > 10,5)" The above example is the same as: output = 1 while (Input[0] <= 10) delay(1) endwhile output = 2 The waitfor() version is just a touch cleaner. Note that the second parameter of waitfor(), the interval, must be a scalar number and cannot be a variable. If you need to use a variable loop time, use the normal while() loop syntax.
5.10 Variables
In addition to channels and V Channels for storing data, DAQFactory also supports several different types of variables: public, registry, private and static. Private and static variables are used in sequences and discussed in the next section. Public variables exist throughout DAQFactory and can be used in expressions or sequences. They can be set using the same mechanisms that channels can be set, even with knobs, switches and other components.
ClearGlobals():
If you need to clear out your globals (and defines decribed below), use the ClearGlobals() function. This clears all globals and defines and basically resets the global variable namespace. Note that the "false" and "true" defines cannot be cleared out, but instead will reset to 0 and 1. You can, however, redefine them if you really wanted to. You can also declare, assign and reference a variable by prefixing it with Var.:
109
Var.MyVariable = 3 In this case, MyVariable is set to 3. If it did not exist, it is declared first. This is most useful in for loops as we'll see later. Note: Var.MyVariable notation is largely provided for backwards compatibility, but is useful in for() loops. One important difference is that to declare and define a string variable using Var. notation, you must name your variable with a name prefixed with "str". In other words: Var.strMyVariable = "some string". There is no way to create a string variable that does not start with "str" using Var. notation. Note: Channels in the default connection also have global scope, so you should be careful to choose different names for your variables and channels to avoid any conflict. If there is a conflict, the variable will take precedence over the channel.
AddValue(Value):
Calling this function adds a value to the history of the variable, moving the current value(s) in the variable back in the array. Value can be a scalar value or an array of values. If Value has time associated with it, the time of each row is inserted as well. If Value does not have time associated with it, the current time is inserted before the data is added to the channel. For array data with multiple rows, you must have time in the array beforehand. Use the InsertTime() function for this. Data will build up until the history length for the variable is reached. The default history length for a variable is 3600. To change, set the HistoryLength parameter of the variable to the new value, fox example: MyVariable.HistoryLength = 100. History only applies in a variable if you use the AddValue() function.
ClearHistory(len):
Calling this function will clear the variables history of all values except for the number of points specified in the function. Leaving this parameter blank clears all the points in the history, which is the same as ClearHistory(0). After clearing, the history will rebuild itself as you call AddValue(). There are several other useful variable functions for inserting and removing array elements. The history length of the variable has no affect on these functions, so you'll have to limit the length of the arrays yourself if needed. These functions only work in the row dimension and do not work in DAQFactory-Express:
Append(Value):
Adds the given value to the end of the array, increasing the size of the array. This is the same as myvar[numrows (myvar)] = Value.
InsertAt(index, Value):
Inserts the given value at the given index of the array. So, if the variable contains {1,2,3} and you do MyVar. InsertAt(1,4), MyVar will become {1,4,2,3}.
RemoveAt(index, [count]):
110
Removes count elements starting at index. So, if the variable contains {1,4,2,3} and you do MyVar.RemoveAt(1,2), MyVar will become {1,3}. Count is optional and defaults to 1.
Push(Value):
Pushes the given value into the top of the array. This is almost identical to AddValue() except the history length is not looked at. It is largely used in conjunction with Pop() to create a stack.
Pop():
Removes the top element of the array (the last Push() usually) and returns that element. y=x.pop() is basically the same as doing y=x[0] followed by x.removeAt(0).
Arrayed Data
Arrayed data can be stored in variables though using either array notation: MyVariable = {5,3,2,5} or by using subset notation to set individual elements-for example MyVariable[3] = 5 When using the subset notation in an assignment like this, existing values are not cleared out. So the following: MyVariable = {5,3,2,5} MyVariable[3] = 2 results in {5,3,2,2} If you are initializing an array using the subset notation, it is recommended that you start with the last value in the array and work towards 0. When you set an array element past the end of an existing array, or in a new array, all intermediary values are set to 0. So, assuming MyVariable was empty, MyVariable[3] = 5 will set MyVariable to {0,0,0,5}. By starting at the end of the array, you allocate the memory for the variable once, rather than reallocating multiple times which is much slower. You can also make 3 and 4 dimensional arrays using similar notation: MyVariable[0][3][1] = 2 will, assuming MyVariable is empty, set MyVariable to {{{0,0},{0,0},{0,0},{0,2}}}. If MyVariable wasn't empty, it would simply set the array element in the 1st row, 4th column, 2nd depth to 2. Like channels, variables can also have time associated with them. When you set a variable to a scalar value ( MyVariable = 5), the time when the variable was set is also stored. This does not occur when setting array values. You can access this time using the GetTime() function, or you can use the following notation: MyVariable.Time or for an array: MyVariable.Time[5] returns the time of the 6th row of the MyVariable array if time is available. This notation also allows you to manually assign a time to a variable: MyVariable.Time = 1h3m To set the time of array values, just use subset notation: MyVariable.Time[3] = 1h3m Remember that only the Rows dimension has time, so the following: MyVariable.Time[3][2] = 1h3m and MyVariable.Time[3][3] = 1h3m will do the same thing because the row subset is the same.
111
As an alternative, you can use the InsertTime() function to quickly insert evenly spaced time values into an array. Note: Graphs, and some other functions require time to be sorted in the array from most recent time back. Element 0 should have the most recent (largest) time. Use the SortTime() function to sort an array based on time into this order. If you are using InsertTime(), use a negative interval to go back in time. Channels also support the .Time notation, but only for reading the time: MyChannel.Time[3] returns the time of the 4th most recent data point of MyChannel. MyChannel.Time[3] = SysTime() is invalid.
Defined constants:
Defined constants are used when you have "magic number", a constant that has some meaning. For example, in DAQFactory, False is equivalent to the constant 0, while True is equivalent to the constant 1. These are predefined constants. Defined constants work a little differently then variables. For one thing they are read only, and once you initialize them, you cannot change them. Also, because they are implemented at a compiler level for speed, the define statement is evaluated when the sequence compiles, not when it runs. Defines have global scope and will override pretty any other names you may have created in DAQFactory, including global variables and channels. The declaration of a defined constant is similar to a variables. Since the define is constant and read only, you have to initialize it in the declaration. For example: Define False = 0 False = 3 // this does nothing Like regular variables, add "string" to create a string define: Define string CompanyName = "AzeoTech" You can use defined constants just like regular global variables, except of course you cannot assign them a new value once declared except by redeclaring them. So if you do: Define x = 3 Define x = 4 x = 5 then x will end up being 4. You can clear defines and global variables by using the ClearGlobals() function. This function erases all defines and globals from memory.
Registry variables:
Registry variables are also a global variable, but they are stored in the Window's registry and therefore persist between different sessions of DAQFactory. There is no declaration of registry variables. Registry variables are accessed by prefixing the variable name with Registry: Registry.MyNumber = 5
112
Registry.strMyString = "data" Registry variables have some limitations: String registry variables must start with "str". Registry variables are a bit slower to access then regular variables. Registry variables do not support arrays. Registry variables only support integers and strings. Integers are double words and therefore must be between 0 and 2^32. Registry variables do not have time associated with them. Uninitialized string registry variables will appear empty, i.e. IsEmpty(Registry.strMyString) will return 1. Uninitialized numeric registry variables return 0. Once initialized, the only way to uninitilize the registry variable is to use the Windows Registry editor and manually remove the variable. Registry variables are stored in HKEY_LOCAL_MACHINE/Software/DAQFactory/Control/ Variables. Setting a string registry variable to an empty string ("") will not uninitilize the variable, but instead will simply store an empty string.
113
Private X = 0 while (X < 10) Output = X * 5 X++ endwhile This sequence simply sets Output to 0 through 45 in steps of 5. Statics are almost the same as Privates, but unlike privates, they do not lose their data when the sequence ends. Instead, when the sequence is run again, the Static will still have the value it was last set to. This type of variable has its particular uses, but is not very common. Declaring statics is just like private and global variables: Static Y = 0 Static String MyCompany = "AzeoTech" The assignment is only made if Y does not already exist. So if this command is in a sequence and you call the sequence twice, the second time through it will not assign 0 to Y, but will simply ignore the statement as Y was declared the first time through. This allows you to initialize the static. Remember that since statics persist even when a sequence stops and restarts that the above lines will only set the variables to the indicated values once. So: Static Y = 0 Y++ ? Y will print 1 to the command window the first time it is run, and then 2 the next time, and so forth because Y only gets initialized to 0 when it is declared and doesn't exist already. If you used a private, 1 would be printed each time because the variable would fall out of scope and be reinitialized the next time the sequence is run. Note: Although Statics retain their data after a sequence stops, they do not retain their value when DAQFactory quits. For this you must use a Registry variable. Note: For backward compatibility, you can still use the Static.MyVar notation to create a static variable, but you will find that static declaration is easier because of the way initialization works with the new declaration methods.
114
For that matter, you can nest while and for loops or other block structures inside of each other. Just make sure everything lines up correctly: OK: if (Input[0] > 5) for (Private.Count = 0, Private.Count < 10, Private.Count++) Output = Private.Count endfor endif NO: if (Input[0] > 5) for (Private.Count = 0, Private.Count < 10, Private.Count++) Output = Private.Count endif endfor
115
116
This is the same as: Private Counter = 0 while (Counter < 10) do something... Counter++ endwhile The for statement is made up of three parts. The first part, Private.Counter = 0 is executed the first time the for statement is reached. In this case, we initialize the Counter variable to 0. By using the Private. in front of the counter variable, we declare (if necessary) and assign the initial value in one step. This saves us from having to do: Private Counter for (Counter = 0, Counter < 10, Counter++) do something... endfor The code between the for and the endfor statements will then execute repeatedly until the second term Counter < 10 no longer evaluates to true. The final term of the for statement gets executed every time the for loops. The first and last term are both statements and can perform anything you can normally do with a single sequence step. The middle term is an expression and should evaluate to a number. For statements can also utilize the break statement to prematurely break out of a for loop, and the continue statement, to prematurely loop back to the for statement: for (Private.Counter = 0, Counter < 10, Counter++) if (Input[0] > 5) break endif if (Input[0] < 3) delay(1) continue endif Output = Private.Counter delay(1) endfor The above example loops up to ten times. If Input ever goes above 5, the loop stops and jumps to any steps after the endfor. If Input is less than 3 than the loop does nothing, but if it is between 3 and 5, Output is set to the current value of Counter. Notice how we include delay() statements in the for loop. Delay or wait statements are needed to prevent the loop from running to quickly and stalling DAQFactory.
117
The infinite loop check ensures that no more than 100 sequence steps execute in any one second. If more than 100 steps do execute in a second, the sequence throws an error and stops. So if you were to run the first sequence, the infinite loop check would very quickly detect the problem and stop the sequence. The loop check is turned off by default as it can stop valid loops. To turn it on or adjust the settings, go to FilePreferences in the main menu. To turn on the infinite loop check, simply check the box labelled Sequence Loop Check?. If you want to increase the number of allowable steps, adjust the Loop Check Count to your desired number of steps. Remember though that, depending on your computer, sequences can execute at least 10,000 steps in a second, so setting the Loop Check Count to a huge number like 100,000 is the same as turning the loop check off. If you are a beginning programmer we recommend turning the loop check on until valid sequences start triggering it, then try increasing the loop check count first before finally disabling the loop check. If you keep the loop check disabled, make sure and save your document before starting any new sequences, just in case you created an infinite loop and end up hanging your computer.
5 Sequences & Scripting5.16 Avoiding being hanged using the infinite loop check
118
It is recommended that all functions have a function declaration so that your arguments have names that make sense. The exception would be when you want to create a function that takes a variable number of arguments. There are several different situations where this occurs: 1) You want to create a function with optional arguments. In this case, you will want to put all the arguments in the function declaration, and then examine any optional ones to see if they were passed by using the isempty() function and setting the default value if not. Note that all the optional arguments must be at the end of the argument list: function IncrementBy(x, by) if (isempty(by)) private by = 1 endif return(x+by) In this example, IncrementBy(4) will return 5 because "by" is optional and defaults to 1. IncrementBy(4,2), however, will return 6 because "by" was specified. 2) You want to create a function with a variable number of arguments. For this an additional private is also created inside of every function called "argc" which contains the number of arguments passed. So: function SumVars() switch case (argc == 2) return(arg0 + arg1) case (argc == 3) return(arg0 + arg1 + arg2) default System.ErrorMessage("Invalid # of parameters") endcase This sample looks at the number of arguments and returns the sum of 2 or 3 values or an error. Notice how we avoided the name "Sum" as a function. This is a reserved DAQFactory function and cannot be used as a sequence name. 3) You want to create a function with several defined arguments and a variable number of arguments in addition to the defined arguments. function PrintVars(string Prefix) switch case (argc == 2) return(Prefix + DoubleToStr(arg1 + arg2)) case (argc == 3) return(Prefix + DoubleToStr(arg1 + arg2 + arg3)) default System.ErrorMessage("Invalid # of parameters") endcase Notice that are arg notation starts at 1 because Prefix takes the 0 spot. However, the argc argument total still includes Prefix. Note: All arguments are passed by value and not by reference. For example, calling our first example above: AddTwo(ChannelX[0]), the value of ChannelX[0] is passed to the AddTwo function, not ChannelX[0] itself. Changes to valuein / arg0 in the AddTwo function do not affect ChannelX. Only by assigning the return value of AddTwo to ChannelX are we able to change ChannelX as seen in the Main sequence above. Note: You can pass a maximum of 20 arguments to a sequence.
119
execute("MyChannel = 3") will set the value of MyChannel to 3. Of course you could have just done MyChannel = 3 directly. Where the advantage comes is when you need to assemble the script while running. For example, lets say you have 50 channels named Ch1, Ch2, Ch3,... and you want to set the first n channels to 4: for (private.x = 0, x < n, x++) execute("Ch"+DoubleToStr(x)+" = 4") endfor Since you don't know what n is when you wrote the script, you couldn't do this without execute. Execute can actually run more than one line separating each line with a Chr(10). For example: private strScript strScript = "global x = 3" + chr(10) strScript += "global y = 4" + chr(10) execute(strScript) Execute allows a lot of flexibility, but really should only be used when necessary for two reasons: 1) it runs slower then regular script because each time the execute() function runs, it has to compile the sequence, and 2) it can make your code harder to read. Just a reminder: the Evaluate() function and the Execute() function are nearly the same, except that Evaluate() must be on the right side of an equal sign or in a place that expects an expression, while Execute() can be anywhere (though really should not be in places that expect an expression). If you put Execute in a place that expects an expression like a screen component, it will always return an empty value. Evaluate returns the result of the expression in the string parameter.
5 Sequences & Scripting5.18 Running commands in a string with the execute function
120
as the error itself. So 'catch("C")' would catch all errors that start with the letter C. Try/Catch statements can be nested as needed. They will also carry through to called functions. If an error occurs in a called function and that function does not handle it, the function will return and the calling sequence will have to handle the error. You can access the text of the caught error with the private variable strLastError. For example, you could generate an error message: catch() System.ErrorMessage(strLastError) endcatch You can also generate your own errors with the throw statement. This can be used as a way to branch, or as a way of creating your own codes: try ... if (Input[0] > 5) throw("U1001 Input went out of bounds") endif ... catch("U1001") endcatch If the error is not caught it will be treated like any other error and stop the sequence and generate an alert. The error string inside the throw is optional. If the throw statement is inside a catch, it will simply rethrow the same error and is the same as throw(strLastError). If it is outside the catch it will generate a default "User Specified Error". Note: If you have multiple catch statements with a single try and you throw in the first catch, the other catch statements may catch the error you just generated: try ... catch("C1001") throw("my error") endcatch catch() endcatch In the above example, if error code "C1001" occurs inside the try, the first catch statement will handle it. This will then execute the throw which will throw another error. But, there is another catch left that catches all errors and this will then catch our new "my error".
Ignoring errors
You can optionally turn off the error catching mechanism by using the ignore statement. You can ignore certain types of errors or all errors. To ignore all errors, simply put ignore("all") at the point you want to start ignoring errors. For example: ... ignore("all") ... // at this point any step that generates an error is simply ignored and execution proceeds to the next step. If you just want to ignore certain errors, you can specify the error code, much like the catch statement: ... ignore("C1001") ... // now only the error C1001 is ignored, all other errors require catching. Again, like the catch statement, only as many characters as specified in the ignore statement are compared to the error. For example, to ignore all standard errors which start with the letter C:
121
... ignore("C") ... // all errors that begin with the letter C will be ignored. The ignore statement does not carry into sequence function calls. ... ignore("all") ... MyOtherSequence() // any errors in the MyOtherSequence will throw an error causing execution to return to this sequence, at which point the error is ignored. ... You can ignore multiple errors by passing an array of strings: ... ignore({"C1001","C1002"}) ... // errors C1001 and C1002 are ignored To clear the ignore statement, simply pass an empty string: ... ignore("all") ... // all errors ignored ignore("") ... // no errors ignored
Threads within DAQFactory and Windows have priority levels. This determines which threads get access to the CPU first when requested. By default, sequences run at the highest priority within DAQFactory along side acquisition loops. This means that if you write an infinite loop in a sequence or anything else that would use a lot of processor power, it will hang everything in DAQFactory but the data acquisition loops. The data acquisition loops have the same priority so share in the CPU usage. The other parts of DAQFactory run at lower priority and are starved out by your sequence. A sequence that is waiting does not require the CPU and allows other lower priority threads to run, so adding delay or wait statements inside your sequence will avoid this problem. Alternatively, you can lower the priority level of your sequence. The thread priority is an option at the top of the Sequence view. There are 6 different levels, 0 through 5. The level of different parts of DAQFactory are displayed when selecting the thread priority. In general, leave the priority at its default value. But if you want to create a sequence that uses a lot of processor power, for example a big while loop analyzing a large data set, put the thread priority at 0 and your sequence will run after DAQFactory is finished with all other tasks. The following loop will actually work fine if the sequence thread priority is set to 0: while(1) endwhile
122
This is an infinite loop that does nothing but use up the CPU. But, if the thread priority is set to 0, it only uses left over CPU power after Windows and DAQFactory are done using the CPU. Tech Note: The 0 priority level is the windows idle priority and runs after everything else in windows. Other levels are intermingled with other applications, though the highest couple of levels will be above most other applications. When in Acquire mode the entire DAQFactory runs at a higher level than other applications. Even with a 0 priority level, an infinite loop running in Acquire mode will starve out all other applications, but will not affect the rest of DAQFactory.
5.22 Auto-Start
If you want a sequence to start automatically when your document loads, you can check the Auto-Start box in the sequence view. Any sequences with the auto-start selected will start as soon as the document completes loading. If you have multiple sequences with auto-start selected, you cannot determine the order in which the sequences will start. If you need to know the order, set one sequence to auto-start and then have that sequence start the other sequences.
Step In: executes the current step, and if that step is a sequence function, steps to the first step of that function Step Out: executes all the steps left in the current sequence function and then stops once control is returned to
the calling sequence
Step Over: executes the current step, and if that step is a sequence function, executes entire function without
stopping, returning control when that function returns (unless of course you have a breakpoint in that function) There is also:
Continue: starts the sequence back up from the current position until another breakpoint is reached or the
sequence stops.
Stop: stops the sequence without executing any more steps Restart: starts the sequence over from the top Display Current Line: this will cause DAQFactory to display the current line about to be executed.
DAQFactory does not automatically do this to allow you to view what is happening on your pages as the sequence is being stepped through.
Clear all breakpoints: this clears all breakpoints on the displayed sequence.
Note: sequences can only be debugged when they are running in their own thread (they were started with a Begin Sequence). A sequence used in an expression in Page Component, a quick action, an event, or elsewhere in DAQFactory will not break at any breakpoints and cannot be debugged.
123
possible or is inconvenient, but it would still be nice to know what the value of a particular variable is at particular point in code, or some other information. For that, you can use the print command to display the result of an expression to the Command / Alert window. The format is the exact same as you would enter in the command line in this window using the ?. For example: ? MyVariable ? "Reached point y in sequence" ? "Value of MyVar is " + DoubleToStr(MyVar) In general, you will probably only want to use the ? statement for debugging as it is somewhat slow. For this reason, DAQFactory provides a simple way to completely disable all the ? statements in all your sequences. The variable, "System.SequencePrint", when set to 0, will cause all the ? statements to be skipped. When set to 1, the default, the ? statements work as described and display to the Command / Alert window. This allows you to liter your code with ? statements to help you debug, and then when everything works, you can simply set System. SequencePrint = 0 in a start up sequence to prevent the ? statements from executing and slowing your code. Note: some sequence problems are caused by timing issues. Having ? statements in your code could change the timing of the execution of various steps of your code resulting in code that works with ? statements enabled, but stops working when disabled. If this happens you should immediately assume that your problem has to do with the timing of your loops.
Functions: Sequence.StopAllSequences(): a quick function to stop all running sequences. If you want to stop all
sequences, logging, PID loops and acquisition, use System.SafeMode to switch DAQFactory into safe mode.
Sequence.SequenceName.CurrentLine: a numeric with the current line being executed. Read only.
124
SendMessage(Message, [Param1], [Param2]): this function sends a message to all the screen
components that are listening for the given message. Please see the section in Pages and Components that discusses user components and component functions for more information.
StartThread(Function, [Name = ""], [Priority = 3]): this function will start the given function
(specified as a string) in a new thread. Its similar to beginseq() except that you can create multiple threads for a single sequence function, and you can pass parameters when starting the thread. The disadvantage of using this method is that you have no feedback or control over the thread except through the following two functions. There is no indication in the workspace that your thread is running and you cannot debug the thread. Function should be a string with the function call with parameters. Name can be any valid DAQFactory name and is used for stopping or getting the status of the thread. You should make sure your threads have unique names. You do not have to name your thread, but you won't be able to stop or get the status of the thread. The function will either need to reach its end, which kills the thread, or you'll need to quit DAQFactory or load another document. Priority matches the numbers listed in the drop down when editing a sequence, where 0 is the lowest, and 5 the highest priority. Example: StartThread("MyFunction(x,3)",MyThread,5) Note that the function call MUST be a string.
StopThread(Name): Stops the given thread if it is running. Throws an error if it can't find the thread. GetThreadStatus(Name): Returns a string with the current status of the given thread, or a message
indicating that the thread doesn't exist. The current status string is similar to the string in the sequence table and includes the current function and line being executed. Note: when creating a user component, you can also use the StartLocalThread(), StopLocalThread() and GetLocalThreadStatus() functions. These functions work the exact same way, but the thread runs in the context of the component and will automatically terminate if the component is deleted. You can also use the same thread name in different components. User components can use the above global functions, but the created thread will run in the global context and won't be encapsulated in the user component. The following functions all start with "System.". Some of these functions must be called from the main application thread, which means they really can only be called from the Quick Sequence action of many components.
Variables: System.AppVersion: set or read the version number of your application. You can use this to do versioning of
your application. By default, a new application is assigned version number 1.0 and every time you save, it will increment this number by 0.01. You can alternatively set this variable to any version number you want. The first time you save after assigning this variable a value, the version number won't be incremented and the value you specified will be used. After that, the number will be automatically incremented.
System.OnScreenKeyboard: set to display or hide the onscreen keyboard. There are two different
keyboards, one that displays as a docking window and works on pages, and another that appears with entry dialogs. Set the low bit of this variable to display the page keyboard, and bit #1 to display the dialog keyboard. In other words, 0 displays no keyboard, 1 displays the page keyboard, 2 the dialog keyboard, and 3, both keyboards.
System.SafeMode: set to 1 or 0 to switch into and out of safe mode. Can be read or written to. System.SequencePrint: set to 1 (the default) to enable the ? statement in a sequence. Set to 0 to have all ?
statements in all sequences ignored.
Functions:
125
System.Quit(): call this function to quit DAQFactory. System.Reboot(): call this function to reboot the local computer. There is way to stop the reboot, and a 30
second delay before it occurs.
System.Shutdown(): call this function to shutdown the local computer. There is way to stop the shutdown,
and a 30 second delay before it occurs.
System.IsDST(): call this function to retrieve the current Daylight Savings Time setting of the system. Returns
1 if DST would be in effect for the current DAQFactory time, and 0 if not. Please note: DAQFactory does not adjust for DST no matter what the system settings. DAQFactory picks up the Windows system time at startup and then after that uses a high precision counter to determine the time. Any changes to the Windows system time, including DST, will not affect DAQFactory time. If DST is in effect when DAQFactory starts, all time in DAQFactory will be DST until you restart. The IsDST() function simply looks at the current DAQFactory time and determines from it if it is the time of year when DST would be in effect or not.
System.IsRuntime(): call this function to determine if we are in runtime mode or not. Returns 1 if in
runtime, 0 if in development.
System.SaveDocument(): calling this function does the same thing as hitting File - Save from the main
menu. It is designed to be used in runtime mode to save user component properties, and thus make user runtime configurable components.
System.HideSystemMenu(): call this function to hide the system menu from the title bar of DAQFactory.
This would mostly be used in Runtime mode to keep a user from exiting the application. Make sure you provide an on-screen button or other method to quit your application.
System.Maximize(): call this function to expand the DAQFactory window to take up the entire screen, similar
to clicking the Maximize button on the window. This is not the same as Full Screen mode which doesn't display the Windows title bar.
System.Minimize(): call this function to minimize your DAQFactory window. System.DeviceConfigDialog(): call this function to display the Device Configuration dialog. This must be
done from the main application thread.
System.Connection.Reset(Name): Resets the given connection. Closes the connection then attempts to
reconnect. This does the same thing as clicking the Reset Connection button in the connection view.
System.Connection.Delete(Name): deletes the named connection if it exists. You cant delete the Local
or V connection. If you want to create a runtime that connects to a computer with a varying IP address, call Delete followed by Add with the new IP address and same connection name. Application: The above three functions can be used in the runtime version of DAQFactory to connect to an unknown remote computer.
System.Connection.Default(Name): sets the default connection to the given Name. For example:
System.Connection.Default("Local")
126
"explore": opens the folder specified in File in Explorer. "open": opens the specified File. In this case, the file can be an executable (which will be run), a document or folder. This is the default. "print": prints the document specified by File. File must be a document. Parameter is used if File is an executable and determines which command line parameters are passed to the executable. It is a string and defaults empty. Path is the default directory used. It is a string and defaults empty. Show determines how the shell will display itself. It is a string and can be: "hide": does not display the executable at all, not even in the Windows task bar. If the executable does not automatically terminate itself, the only way to stop it is using the Processes tab of the Windows Task Manager. This setting is best used when printing documents. "minimize": opens File, but minimizes it. "maximize": opens File and maximizes the window. "normal": opens File in whatever way it normally opens. This is the default setting. "noactivate": same as normal, but DAQFactory remains on top and in focus.
System.Sound.Play(.wav file name): plays the given wave file. If a file is currently playing, that sound
will stop and the new one will start
System.Sound.Stop(): stops any playing sound System.DelayUpdate(): causes the system to stop redrawing the current page. This is useful if you want to
move a number of components around at once without having the user see each individual component move. Use ResumeUpdate to continue drawing the screen.
System.ResumeUpdate(): allows the system to continue updating the current page. We strongly
recommend using a try/catch block around a DelayUpdate / ResumeUpdate pair to ensure that pages are updated if there is an error: try System.DelayUpdate() ... do a bunch of stuff System.ResumeUpdate() catch() System.ResumeUpdate() endcatch
System.ColorSelectDialog() : displays the standard color selection dialog and returns the selected color or
an empty value if the user hits cancel.
System.HelpWindow(HTML file, [x1], [y1], [x2], [y2]): displays a window with the specified
HTML file. X1, Y1, X2, Y2 determine the coordinates of the window. The default is centered.
System.NoteDialog(): this displays the quick note dialog just as if the user selected Quick-Note from the
main menu. Nothing is returned. The result is added to the Note history. This must be called from the main application thread.
127
HTML help file to display. This function returns one of the following depending on which button the user presses: OK, Cancel, Ignore, No, Yes, Abort, or Retry
System.ErrorMessage(Message): this generates an Alert within DAQFactory with the given message.
This does not generate an error within a sequence, but just sends the given message to the Alert window. To generate a catchable error in sequence code, use throw(). Note: although you can call most of the above functions from a sequence, for the ones that require a user response (MessageBox, HelpWindow, EntryDialog and ColorSelectDialog) you must be very careful. First of all, having windows popup without the user clicking on something can be annoying to the user, but there are other issues: Two big things to watch for are loops that repetitively call these functions, and using the wait() function. The best way to show the potential problem is with examples: while (1) page.page_0.backcolor = System.ColorSelectDialog() .. some other quick stuff delay(1) endwhile In the above loop, the user will essentially be prompted for a color every second. Because the delay is so short, and the color select box is modal, meaning the user can't access the reset of DAQFactory while it is displayed, the user won't be able to stop the sequence because the color box will redisplay every second. This is compounded more if you use a wait() function instead of delay because the wait() will go to 0 because the user interface is slow, and the user will be continually prompted and will not be able to escape. So, in general NEVER use wait() in a sequence that contains one of these user interface functions. A few other things to think about: - If another sequence stops a sequence that is waiting for a user response, the sequence will stop, but the window requesting the user response will remain. When the user closes this window, any return value is discarded - If another sequence calls one of these functions while a window is already displayed, the new window will appear on top and will have to be dismissed before the user can get back to the first one.
OnAlert(): called when an alert occurs. An alert is anything that would appear in the command / alert window as
an alert. This does not include things printed there using ?, nor does it include errors that are caught in code using try/catch. The private variable strAlert is passed into the event which is the exact text of the alert as it appears in the Command / Alert window, but without the timestamp.
OnHelp(): called when the user presses the F1 key invoking help or when you select Help-Help Topics. Windows
often captures the F1 key before it calls OnChar() or OnKeyUp(), so this is a way to use the F1 key for another purpose. To avoid displaying the DAQFactory help, put return(1) at the end of the sequence to indicate that default
128
OnShutDown(): called when DAQFactory exits, or when a document is closed. Because of where this occurs in
the Windows event structure, you cannot perform any windows based tasks here. For example, you cannot display a message box. You can, however, do things like adjust outputs and other similar clean up. Any returned value is ignored. There is no way to stop the shut down procedure. These events only apply when the page view is displayed and in focus. For applications running in Runtime mode, this is pretty much all the time.
OnChar(Char, Shift, Ctrl): called when the a key is pressed. The differences between this and the OnKeyUp
() event are subtle. The OnKeyUp() event won't detect a repeated character when a key is held down, but it will better detect special keys like function keys. The Char parameter is the numeric key code generated; Shift is 1 if the shift key is down; Ctrl is 1 if the control key is down. Returning 1 from this event will cause DAQFactory character events to be skipped. Note that which events DAQFactory does with OnChar and which with OnKeyUp are not documented because they may change at any point. If you want to process all keystrokes, make sure and put return(1) at the end of both the OnChar() and OnKeyUp() events.
OnContextMenu(Loc, Shift, Ctrl): called when the context menu is triggered. Typically, unless the user
has reassigned their mouse buttons, this is when the user right clicks. It also occurs when the popup button is pressed on newer keyboards. The Loc parameter is an array with two columns containing the current X and Y position of the mouse. Shift is 1 if the Shift key is pressed; Ctrl is 1 if the control key is pressed. Returning 1 from this event will cause DAQFactory processing of this event to be skipped.
OnKeyDown(Key, Shift, Ctrl): called when a key is pressed. The Key parameter is the keyboard scan
code for the key; Shift is 1 if the shift key is down; Ctrl is 1 if the control key is down. Most of the normal keys match their ASCII equivalent. For other keys, you can search the internet for Windows key codes, or simply create an event that sets a global variable to Key, display that global variable in the watch, and simply try different keys. Returning 1 from this event will cause DAQFactory processing of this event to be skipped.
OnKeyUp(Key, Shift, Ctrl): called when a key is released. Everything else is identical to OnKeyDown() OnLButtonDblClk(Loc, Shift, Ctrl): called when the left mouse button is double clicked. What constitutes
a double click is determined by windows. The Loc parameter is an array with two columns containing the X and Y position of the mouse. Shift is 1 if the Shift key is pressed; Ctrl is 1 if the control key is pressed. Returning 1 from this event will cause DAQFactory processing of this event to be skipped.
OnLButtonDown(Loc, Shift, Ctrl): called when the left mouse button is pressed. The Loc parameter is an
array with two columns containing the X and Y position of the mouse. Shift is 1 if the Shift key is pressed; Ctrl is 1 if the control key is pressed. Returning 1 from this event will cause DAQFactory processing of this event to be skipped.
OnLButtonUp(Loc, Shift, Ctrl): called when the left mouse button is released. The Loc parameter is an
array with two columns containing the X and Y position of the mouse. Shift is 1 if the Shift key is pressed; Ctrl is 1 if the control key is pressed. Returning 1 from this event will cause DAQFactory processing of this event to be skipped.
OnMouseMove(Loc): called when the mouse moves on a page. The Loc parameter is an array with two
columns containing the current X and Y position of the mouse. Returning 1 from this event will cause DAQFactory processing of this event to be skipped. It will not, however, cause Windows handling of this event to be skipped.
OnMouseWheel(Loc, Delta): called when the mouse wheel is moved while on a page. The Loc parameter
is an array with two columns containing the current X and Y position of the mouse. Delta is typically either -120 or +120 depending on which direction the wheel is spun. Some mice with finer wheels may return smaller values. This event is typically triggered for each click of the wheel, but again, with finer wheels, the event may be triggered more often. Returning 1 from this event will cause DAQFactory processing of this event to be skipped. It will not, however, cause Windows handling of this event to be skipped.
OnPostDraw(DC): called after DAQFactory renders the current page. This event passes in a private variable
named "DC" which you can use with the drawing functions as described in the Canvas Component.
OnPreDraw(DC): called before DAQFactory renders the current page. This event passes in a private variable
named "DC" which you can use with the drawing functions as described in the Canvas Component. This is the one
129
event in this list that runs in a secondary thread along with the drawing of graphs and images. If your routine is slow, it will not slow DAQFactory, but will slow the rendering of graphs and could cause other rendering abnormalities.
OnRButtonDblClk(Loc, Shift, Ctrl): OnRButtonDown(Loc, Shift, Ctrl): OnRButtonUp(Loc, Shift, Ctrl): these three events are identical to their LButton counterparts except they
apply to the right mouse button.
130
the two channels, LWC_calculation and CDP_NumbConc. For example, r4 is calced from rGEO which is calced from r which is a constant array. It is terribly inefficient to be calculating the same values over and over again. Instead, a separate sequence should be created to pre-calc these values and that sequence called once when the application loads. These values could then be stored in global variables and used anywhere. 6) A for() loop is usually preferred to a while() loop when you are simply looping a certain number of times. Although they result in the same thing, using a for() loop keeps you from accidentally forgetting to increment the counter variable.
AppendValue(array, value): this sequence function will simply add the given value to the end of the array:
// Gets the index value for the end of the array Private Index = NumRows(arg0) // Adds the new value at the end of the array arg0[Index] = arg1 // Returns the modified array return(arg0) Of course its easier (and much faster) just to do it in place in one line then use this function: array[numrows(array)] = newvalue
AddHistory(array, value): this does almost the same thing as AppendValue() except adds the value at the
beginning of the array, moving all the other elements back. As of 5.7 you can use the AddValue() function of a variable to do this for you. // move everything out of the way arg0[1] = arg0 // and put new value in place arg0[0] = arg1 return(arg0)
131
FindValue(array, value): searches through the array for the value and returns the index of the first
occurrence. As of 5.70 we now have a search() function that does this for us. All we do is Search(array == value). That said, the old method shows us some nice tricks with arrays that may apply to other cases, so definitely read on if you are interested: There are two ways to do this, the slow way...: // The for loop searches through the array until it finds the specified value. Private a Private FoundAt = -1 for(a = 0, a < NumRows(arg0), a++) // If the value is found perform the following code. if (arg1 == arg0[a]) // Sets the variable FoundAt to the index of the array where the value was found. FoundAt = a // Since the value was found break out of the loop break endif endfor return(FoundAt) and faster way: Private FoundAt = GetTime(Max(InsertTime(arg0 == arg1,0,1))) if ((FoundAt == 0) && (arg0[0] != arg1)) FoundAt = -1 endif return(FoundAt) For example, if the array had 100 values and the value you were searching for was the last value in the array, on our test computer the first slow way takes 16 milliseconds. The second way takes 0.8 milliseconds. And it gets worse with bigger arrays. If the array is 1000 values, the first method takes 183 milliseconds, while the second way takes 1.9. So while the first method took slightly more than 10 times as long to search 10 times as many values, the second fast way took only slightly more than twice as long. Go up to 10,000 values and its 4.5 seconds vs 5 milliseconds, a factor of almost 1000! How the fast way is done requires a bit more explanation. If possible you always want to avoid doing loops in DAQFactory. DAQFactory is a scripted language, and therefore is not particularly fast. However, the built in functions provided are all written in C and are therefore VERY fast. The trick is figuring out how to use the functions to get what you want. In this case we want to find a value in an array and return the index. So: 1) arg0 == arg1 : this returns an array of 1's and 0's the same size as arg0 (remember arg0 is the array, and arg1 the value). There will be a 1 everywhere the value in arg0 equaled arg1. For example: {1,4,6,2,6} == 6 would return {0,0,1,0,1}. 2) InsertTime(...,0,1) : the insert time function is normally used to insert time into a value. Variables in DAQFactory are actually made up of two arrays, one with the data, and one with the time. In this example we don't need the time, so we are going to use that second array to store the index into the array. The 0 means start at 0, and the 1 means increment by one for each index in the array. We'll use this in a minute... 3) Max(...) : the max function finds the maximum value in an array. In this case, our array is 0's and 1's so it will return 1 if the desired value is in the array, and 0 if it is not. Where Max becomes handy is in the next step... 4) GetTime(...) : the Max() function, in addition to returning the maximum value in an array, also returns the time of the first instance of that maximum value. In this case, we've inserted the index of each point into the time part of our array, so the Max() function is actually returning the index as well. This index is, however, in the time part of the result, so we have to use the GetTime() function to retrieve it. At this point, we have the index of the data point in the array that equals our desired value. But we're not quite done... 5) What happens if the value doesn't exist in the array? In this case, arg0==arg1 would return an array of 0's, Max would return 0 and GetTime() would also return 0. So, if our first line sets FoundAt to 0 one of two things happened. Either the value actually exists at index 0, or it was not found. So, we just do an if to see. If FoundAt is 0 and the first point in the array does not equal the desired value then the value doesn't exist, so we set FoundAt to -1 to indicate no find. Now we are done.
132
There is actually another way to do step 5: if (Max(arg0 == arg1) == 0) This is probably slower though, at least when the arrays get bigger since the original method only examines two values, while the == and Max both would have to examine every value in the array. One note: this function does not work on two or three dimensional arrays because time is only tracked along the first dimension. That said, there are still ways to search quickly without using a for() loop. How this is done depends on whether you want to return the row with desired value or the column, or if both, which gets priority. The concepts are the same, except you'd probably use the MaxCols() or MaxDepth() function and then use the Transpose() function to get the array into the Rows dimension to use the Time indexing trick. That all said, there are certainly plenty of cases where a loop is required, so don't think that you can't use loops in DAQFactory. Just try and use DAQFactory's built in functions whenever possible.
InsertValue(Array, Index, Value): Inserts the given value into the array at the given index, pushing
anything above it out of the way // Gets the index value for the end of the array Private ArrayEnd = NumRows(arg0) - 1 // Shifts down the values to create space for the new value arg0[arg1 + 1] = arg0[arg1,ArrayEnd] // Inserts the value into the array before the insert value index arg0[arg1] = arg2 return(arg0)
Answer:
To start a sequence at the second, just add this to the first line of the sequence: waituntil(floor(systime()) + 1) waituntil() waits until the specified time. By taking the floor() of systime() we get the .000 of the current second. We then add one to wait until the beginning of the next second.
VI
134
135
Channel Name: This contains the name of this channel which will be referenced through DAQFactory for
displaying and analyzing data. Like all names in DAQFactory, the channel name must start with a letter, and contain only letters, numbers and the underscore. DAQFactory will prompt you when applying your changes if you have any invalid channel names. We suggest using a descriptive name. Consider either separating multiple word names with an underscore like: Inlet_Temperature, or using upper lower format like: InletTemperature.
Device Type: Here you will select the type of hardware device. The list of possible choices depends on what
device drivers are installed on your system. Typically, these refer to a hardware manufacturer, or special type of I/ O (like Serial).
D#: This refers to the device number. Only certain device types use this parameter. Refer to the documentation
on your particular device type to determine the appropriate values.
I/O Type: This helps define the class of data being received and has different meanings depending on your
device. For example, most DAQ boards will have "A to D", "D to A", etc.
Channel #: This specifies the exact I/O channel number. Again this is device type specific, but typically refers
directly to the channel described on your hardware's pinout. Some devices, OPC for example, do not use this parameter.
Timing: The timing value determines how often an input channel is read. It has no meaning and cannot be
entered for output I/O types. The units of timing are in seconds. You can enter a value of 0 for timing, in which case the channel will only be read when a Sequence read channel command, read(), occurs on that channel or through other device specific methods.
Offset: There are cases when your hardware I/O might be somewhat slow. In this case, you probably do not
want to hold up your other I/O for this slow hardware. By providing an offset value for your slow hardware you can have all your data read at the same timing interval, but stagger the reads in a predictable manner to allow the slow hardware to finish without holding up the fast I/O. For example, you could set all your fast I/O channels to a timing value of 1.0 and an offset of 0.0. Then you would set your one slow channel to a timing of 1.0 and an offset of 0.1. This way your fast I/O will always occur right on the second, and your slow I/O will not start until 100 ms later, which should give you fast I/O time to complete. The units for this column are also in seconds.
Conversion: Conversions allow you to put your data into more useful units. Conversions are discussed a little
bit later on. In this column you will select from the list of available conversions, or select None to leave your data in raw form. Remember, you can always put your data in just about any units from within DAQFactory as well.
136
History: To allow you to display graphs and do data analysis, DAQFactory keeps a history of the data from all
your channels in memory. Unfortunately, computers do not have an unlimited memory, and rather than assume some arbitrary limit to the amount of data that is remembered, the history column allows you to specify the number of data points that are kept in memory. You can therefore set the history amount to a large number for your important channels and a smaller number for the less important channels. As a reference, each data point within DAQFactory uses 16 bytes of memory. So a history of 86400, or a days worth of 1 hz data, will take just under 1.4 meg of memory. The same is true for image and spectral data, except that you have to multiply the history by the n umber of data points per spectrum or image. All memory is allocated as soon as the first data point is added to the channel. Use this in combination with Persist to extend the amount of data available to your graphs and calculations.
Persist: In addition to the history and separate from data logging, you can opt to keep a larger amount of historic
data from a channel on your hard disk for easy retrieval. The Persist field specifies how many data points are kept on disk. Since hard disks are significantly larger than RAM, you can make this number very large and thus have quick access to lots of data. Please see the next section on channel persistence for a more thorough discussion of this parameter and how it works with History. This parameter is optional and defaults to 0, which means only the channels history in memory is used for graphs. Note that channel persistence does not work with string, spectral or image type data.
Avg?: If this is checked, then the data being stored to disk will be averaged first. This is a simple way to reduce
the amount of data being stored without ruining the precision of your measurements. The amount of averaging is determined by the next column.
# Avg: This column determines the number of data points that will be averaged before the average is stored. The
average is a boxcar average, not a running average. This column can only be edited when the previous column is checked.
Quick Note / Special / OPC: This column can have different meanings depending on the device type and I/
O type specified. For most channels, the column simply contains the Quick Note where you can specify short details about the channel. For some I/O types on certain legacy devices, an ellipsis (...) button will be displayed. If you click on the ellipsis, a dialog will appear allowing you to set certain parameters for the channel. The Command I/O type will almost always have parameters. See the documentation on the device driver for more details on exact commands. For OPC devices, an ellipsis will also appear. Clicking on this will open a dialog that allows you to browse for your OPC tags. Once selected, the tag will be displayed in this column in the format: server;host;tag. You can always manually enter these values in the table. Please see the section on OPC for more information. Other devices may use this column for other channel specific details.
DAQConn?, determines if the channel data is being sent to DAQConnect web service. Check this box to mark the
channel. Please see the section on DAQConnect and www.daqconnect.com for more information.
DC Hst: determines how many data points are kept on the DAQConnect server for historical viewing. This number
is limited by the plan you select. You can enter -1 to have DAQConnect automatically apply an even amount to all of your tags based on your plan, or you can specify exact amounts for each channel allowing you to have more data retained for certain channels.
DC Intvl: determines how often the channel data is sent up to DAQConnect. This is in data points. So, if you are
taking data once a second and you put a value of 10 in this column, every 10th data point is sent. This is to allow you to take data at a faster rate than it is sent to DAQConnect. Please note that DAQConnect may limit the spacing of data points being sent to it. If you need to send high speed data such as streamed data, you should contact DAQConnect to arrange for a special plan.
Mod Slave #: If you are using the Modbus Slave protocol, this assigns a particular Modbus address to the
channel. Please review the section on the Modbus Slave protocol for more information.
# Hst: If your memory is limited but you still need to be able to keep a long history, you can set this column to a
number larger than 1. This column tells DAQFactory how often to update the history of this channel. If this column contains 10 on a 1 hz channel, then the history will contain a bunch of points separated by ten seconds. The latest data point is always kept in the history (i.e. at subset [0]).
Brd?: This determines if the channel data is broadcast on DDE. DDE must be enabled through Document-Settings
first. See the chapter on networking for more information. This determines whether the channel data is broadcast to remote copies of DAQFactory that are connected to this copy of DAQFactory using the slim data stream. This is discussed more in the chapter on networking.
137
# Brd: In low bandwidth applications, or any application where you want to reduce your network load, you can
set the interval in which data is broadcast to other copies of DAQFactory. A value of 1 for this column results in all data being transmitted. A value of 0 results in no data being transmitted even if connected via the full data stream. A value of 2 results in every other data point being transmitted, and so forth. No averaging occurs, and this has no affect on the data storage. This affects both the full and slim data streams.
Group: This determines which group the channel belongs to. Channel grouping only affects how the channel table
and workspace are organized and have no effect on the rest of DAQFactory. Using channel groups is discussed in the section on Channel Groups. Additional channel parameters exist that can only be edited in the Channel View. Once you have entered all your channels, or have made any changes to existing channels, make sure you press the Apply button to start taking data. Press the Discard button to ignore any changes and revert back to the page view. If you forget to click Apply and try and switch to a different view, you will be prompted to apply you changes.
138
The amount of disk space used for a particular channel is its Persistence Length, which is only limited by your available disk space. The file is preallocated and optimized so that the Persistance Length is completely scalable without a performance hit. This means you could keep 10 million data points on hand for your graphs and calculations without having to worry about loading your data into DAQFactory from a logging file. Using channel persistence is as easy as setting the Persistence Length for each channel. This can be any size up to the limit of your hard-drive. Each data point takes up 16 bytes, so a Persistence Length of 100,000 will take 1.6 meg of disk space. The files are created in a subdirectory called Persist under your DAQFactory installation directory. The file is preallocated, meaning a Persistence Length of 100,000 will create a 1.6 meg file immediately, even though you haven't accumulated 100,000 data points yet. Accessing persistence data is done completely transparently. When you request some channel data, for example by doing MyChannel[0,4000], DAQFactory will first check the channel's history in memory as determined by its History Length and retrieve it from there if it is all available. If not, it will automatically go to the disk and retrieve it from the disk. So, if your History Length is set to the default 3600, MyChannel[0,4000] will retrieve the data from the persistence file, but MyChannel[0,3000] will retrieve it from memory. The only exception is when you do not subset at all, i.e. MyChannel. This will retrieve the history as determined by the History Length. This is largely to keep you from accidentally retrieving a huge number of data points from the persist file inadvertently, which would occur because of DAQFactory's expression colorization as you typed your expressions. This last paragraph is an important point when determining what to set History and Persistence length to. If you don't need to keep a lot of historical data for a particular channel and you don't care if the historical data is reset the next time you start DAQFactory (separate to what is logged of course), then just use History Length and set Persistence Length to 0. If, however, you do want to keep a lot of historical data, or you want your data to automatically be available if you restart DAQFactory, then set your Persistence Length to the desired amount. Even if you use channel persistence, you will want to set your History Length to a non-zero value as well, otherwise DAQFactory will be forced to go to the disk every time it needs data from the channel. At a minimum, your History Length should be 1, so that all [0] requests for the most recent value pull from memory, but remember it only takes 16 bytes per data point, so if you have a display of the mean of the last 100 points, you probably should set your History Length to at least 100. What exactly to set it to depends on the situation. Just remember that data retrieved from memory is much faster than data retrieved from the persistence file. At the same time, we recommend keeping History Length below 50,000 to 100,000.
139
Because specifying just a channel name with no subsetting only returns a maximum of History Length points, doing NumRows(MyChannel) will not return the full number of data points available from the persistence file, but instead the number of points available up to the History Length. To retrieve the full number of data points in the persistence file, use the GetHistoryCount() function of your channel: Len = MyChannel.GetHistoryCount() If you want to analyze a very large subset of your data, say over a million data points (or perhaps less), you should avoid doing it directly in a page component. For example, if you want to display the maximum value read over the last year at 1 hz, you should not do: Max(MyChannel[0,31536000]) in a Display Value Component as the component will force those 31 million data points to be loaded into memory every time it refreshes. Instead, you should use a sequence and calculate it once there and store the result in a variable that is displayed. Of course this will still require DAQFactory to load 31 million data points requiring 504meg of memory, so you should think about alternative ways to do this. For example, load and analyze the data in smaller chunks: Private x Private maxs for (x = 0, x < 100, x++) try maxs[x] = max(MyChannel[x * 100000+1,(x+1)*100000]) catch() endcatch endfor return (max(maxs)) In this example, we determine the max of chunks of 100,000 data points and put it in the maxs array, then find the max of that array. This keeps our maximum memory load to 1.6 meg instead of 160 meg required if we did it in one step. Notice that we use a try/catch block as we may subset past the end of the persistence file and don't want an error, just an empty array item. You could also use ignore("all") if you didn't need any other error handling. A better way would be to simply use GetHistoryCount() to avoid subsetting past the end. There are other ways of doing this. For example, you could precalc the max on startup and then use the channel event to update the max if needed. With channel persistence, DAQFactory makes very large data sets easy to deal with, but you still have to think about what you are doing and what DAQFactory is doing for you. Because systems are different, we cannot make it all completely automatic. A common use for channel persistence is to allow the user to scroll the graph back a long distance in time. One way to do this is to create two variables for the graph start and stop time and use one of the many components available to change these variables. When using this method, the variables should be used both in the bottom axis scaling and in subsetting the channel as described above. So, if your variables were STime and ETime, you'd do MyChannel[STime,ETime] vs Time. If you don't subset like this you will waste a lot of processor power loading data from the disk that is never used, so try and only request the data that is needed. This is actually good practice even if you are retrieving data from memory. Another use of channel persistence is to allow you to restart DAQFactory without losing the data used for graphs and calculations. Since the persistence files remain when DAQFactory stops, they are available when it restarts so even though no data may have been acquired, your graphs can automatically retrieve the older data from the persist files. The channel table in the channel view will only display up to the History Length data points. Again, this is so you don't inadvertently retrieve a large number of data points.
140
labeled All will also appear. This tab lists all channels irrespective of group. There is also a column in the channel table labeled Group. You can use this column to quickly change the group of a channel and even create new groups by entering in new group names here.
141
Timing = 1, Offset = 0
Timing = 10, Offset = Data is read every ten seconds, on the second. 0
142
Timing = 10, Offset = Data is read every ten seconds starting five seconds 5 after a Timing 10, Offset 0 would read.
All channels with the same timing and offset information are grouped together internally, and each time the timing interval comes up, DAQFactory will read each of the channels in the group in an unpredictable order (although it will read together all channels from a single device). If you have a channel connected to a piece of hardware that is slow to read, the reading of all channels afterwards will be delayed. Offset provides the mechanism to prevent this. If, for example, you have a group of channels you'd like to read at 1 second interval and one of those channels takes half a second to read, you could give all the fast channels a timing of 1 and an offset of 0, then give the slow channel a timing of 1 and an offset of 0.1. This way all your fast channels will read right on the second. The slow channel would begin reading 100ms later, which gives the fast channels plenty of time to finish reading. Technical Detail: Because each timing / offset setting runs in a different thread of execution of the computer, you can actually simply put a slow channel in any offset, even say 0.01, and provided they aren't on the same device driver (unless the driver is designed for multithreaded access), the reads will occur concurrently. If they are on the same device, you can set the offset at around 40 ms and the slow channel will read when the other channels are done, or 40 ms after they start, whichever is greater. The 40 ms comes from the maximum observed latency in timing plus some additional cushioning.
Network security
When using DAQFactory networking (meaning adding a new Connection), data is encrypted to the level allowed by your location and your Windows installation. The encryption key is based off of the passwords you provide for networking, so it is important to put at least a minimal password in. You can protect yourself further using a hardware or software firewall. DAQFactory uses ports 2345 and 2346 to communicate over the full data stream, and ports 2347 and 2348 to communicate over the slim data stream. If you block traffic on ports 2345 and 2346, users
143
on the other side of the firewall will not be able to connect using the full data stream, but can still connect using the slim data stream. Personal software firewalls are cheap (or even free), readily available, and pretty easy to setup. Just make sure you can block individual ports with your firewall. Network passwords are discussed in the section on document settings.
AddValue(Value):
Calling this function manually adds a value to the history of the channel. Value can be a scalar value or an array of values. If Value has time associated with it, the time of each row is inserted as well. If Value does not have time associated with it, the current time is inserted before the data is added to the channel. For array data with multiple rows, all rows are assigned the same time. Use the InsertTime() function on value if you want to insert a different time. Application: The AddValue() function is typically used in sequences that acquire data using unusual methods. For example, many of the serial devices have device functions which will read a batch of points across multiple channels with a single call. Once the data is acquired, you can use the AddValue() function to add the data to the appropriate channels. For example: // read three consecutive tags from a Modbus device: Private.In = Device.MyModbus.ReadHoldingFloat(1,600,3) // ReadHoldingFloat returns a 2 dimensional array, but with 1 row, 3 columns. // now add the three values to three different channels: CoreTemperature.AddValue(Private.In[0][0]) WaterTemperature.AddValue(Private.In[0][1]) WaterPressure.AddValue(Private.In[0][2]) AddValue() does not convert the value from the channel's conversion. It will, however, cause the data point to be logged to any logging sets, broadcast to any remote systems, and alarms to be calculated.
GetHistoryLength():
144
Returns the number of historical data points in the channel, essentially the number of rows. This function differs from NumRows() in two ways: NumRows() works on channels, variables and any other array, but for channels will return the number of historical data points, but only up to the channel's history length. GetHistoryLength() only works with channels, but will return the length including any persisted data as well and is much more efficient then using NumRows(MyChannel[0,1e7]) which will achieve the same thing but require the entire MyChannel persisted history to be loaded into memory. Bottom line: use GetHistoryLength() to retrieve the number of data points in a channel, and NumRows() for all other arrays.
Time:
This is not quite a function, but allows you to request the Time associated with the channel instead of the data. This is the same as GetTime(), but offers more when used with variables (as explained in the section on variables under Sequences & Scripting): MyChannel.Time returns the time of all data points in the history of MyChannel (the same as GetTime(MyChannel)) MyChannel.Time[0] returns the time of the most recent data point in MyChannel (the same as GetTime(MyChannel [0]))
Variables:
All the properties of a channel except the channel name are editable from script with the following variables. To edit the channel name you must delete the channel and recreate it. Changes to some of the properties, namely device, device number, i/o type, channel, strSpecifier, timing and offset, will not take effect until you call the Channel. Restart() function. This function, described in the next section, stops the acquisition and restarts it with the new parameters. The values may appear to be changed, but the changes do not affect acquisition until the Restart() call. Like the functions above, all these variables are preceded with the channel name and a period. strDevice: this is the name of the device as a string. If you change this value, make sure and change the IOType as well. Although two different devices may have the same IOType string name like "A to D", internally they may be coded differently. DeviceNumber strIOType: the I/O type name as a string. Channel Timing Offset HistoryLength PersistAmount: remember that changing this value will clear the persistence file of any existing data. ModbusRegister HistoryInterval strConversion: this should be set to "None" when no conversion is desired. Broadcast: 0 or 1 BroadcastInterval Average: this is 0 if averaging is off, or the number of data points to average. strSpecifer: this is the quick note / special / opc column often used by the device. strQuickNote2: another space to store some info about a channel. This is typically this is one liner information. strNote: yet another space for random info about a channel. This is typically more in depth info about the channel.
145
strGroup: the group the channel belongs. Note that channel groups are created on the fly, so you simply assign a channel a new group name to create a new group. Changes to strGroup may not update in the workspace as dynamic, scripted changes to strGroup are typically used in fully scripted apps in conjunction with the Channel.ListAll () function described in the next section. strEvent: the sequence script that gets executed when the channel receives a new data point.
Add(channel name, [device = "Test"], [device number = 0], [i/o type = "A to D"], [channel = 0], [timing = 0], [offset = 0], [specifier = ""], [group = "Main"]): adds a
new channel to the local connection with the given name. If the channel already exists another is not created, but instead the current channel is updated with any of the information provided. Only the channel name is a required parameter. In cases where you are dynamically creating channels to use solely with AddValue(), this is all you should need to set, unless you want to group your channels (see ListAll()). For the device and I/O type parameters, you should pass a string with the desired device name or I/O type. Remember if timing equals something other than 0, you must call Restart() to start the timing loop. Once you have a channel created, you can change parameters dynamically using the execute command: Execute(strMyChannel + ".HistoryLength = NewHistoryLength") Where both strMyChannel and NewHistoryLength are your variables. Of course, if you know the channel name at design time, you should just do: MyChannel.HistoryLength = NewHistoryLength
AddValue(device name, device number, io type name, channel, value) This works just like
the channel version of AddValue() described in the last section, except you don't have to know the channel name for it to work. Instead, you should provide the name of the device type, the device number, the name of the I/O type and the channel to specify which channel you wish to add the value to. For example: Channel.AddValue("Test",0,"A to D",0,5) This function will return an error if the specified channel does not exist. This function is most commonly used within user and communication devices when you wish to create a generic driver.
Delete(channel name): removes the channel with the given name if it exists. Remember, if the removed
channel has a timing other than 0, you must call Restart() to remove it from the timing loops. Failure to do so will create excess overhead.
ClearAll(): removes all the channels in the Local connection. Remember if any of the channels have a timing
other than 0 you must call Restart() to stop all the timing loops.
146
Read(string Array): takes an array of strings containing channel names and reads those channels. For
example: Channel.Read({"myChan", "myOtherChan"}) This is similar to doing read(mychan) and read(myOtherChan), except that by doing it in a single call, drivers are able to optimize reads, for example Modbus reads can be optimized into a single call.
ReadGroup(groupName): takes a string containing the name of one your channel groups and reads all the
channels in that group. For example: Channel.ReadGroup("myGroup") This works just like Channel.Read() except uses the channel's group setting instead of taking a list of channels. Make sure you do not have any output channels in the Group!
Restart(): this stops all the timing loops and restarts them with any changes from the above functions or variable
changes with channels described in the previous section. Restart() is not terribly fast, especially when dealing with slow devices as it has to wait for the current loop to complete. For this reason, the loops are not restarted automatically when a parameter changes or a new channel is added.
ListAll([group]): returns an array of strings containing the names of all the channels. If group is provided,
only those channels in the given group are returned: Channel.ListAll("Main"). Used in conjunction with Execute () or Evaluate() you could easily apply things across groups of channels.
Entering Conversions:
To create conversions you will use the conversion table. To access the conversion table, click on the CONVERSIONS: label under the desired connection. The table only has two columns, the conversion name and the expression for the formula of the conversion. To add a new conversion, click on the Add button. Enter in a name for the conversion. Next type in the formula. The formula cell is an expression type cell. This type of cell works the same as any expression box used in DAQFactory. However, it should be noted that for all Connections except local, only channels for the given connection will be listed. You can print the conversion table by selecting File - Print from the main menu.
Using Conversions:
A single Conversion can be used on multiple channels. This is especially useful if, for example, you have ten pressure transducers that are all 0 to 500 psi corresponding to a voltage of 0 to 10V. If your A to D channels were 16 bit and output 0 to 65535 corresponding to 0 to 10V, you would create a conversion with this formula to convert from the raw A to D number to psi: Value / 65535 * 500 The word Value is used wherever you want to substitute the raw channel value in the formula. You can use channels by name as well, as long as they exist on the same connection. You can also use almost all the available functions. The only ones that won't work are the ones that process an array (unless the conversion is for a spectrum) and the ones that modify time. Conversions can also be used to convert output channels. As an example, lets make the last example an output. If 2011 AzeoTech, Inc.
147
you have a pressure controller that takes 0 to 10V for a pressure setting of 0 to 500 psi, and your 16 bit D to A takes a value from 0 to 65535 corresponding to 0 to 10V, you would enter the following formula for your conversion so that you could enter psi values for set points: Value / 500 * 65535 Notice how this is the reverse of the previous formula. For outputs, we want to take useful units and convert them into the arbitrary units of your hardware. For inputs we do the reverse.
Applying Conversions:
To apply a conversion to a channel, open the channel in the channel view, or open the channel table and find the desired channel and select the conversion from the drop down list. Note: Your data is sacred, so logging sets give you the option of storing your data before converting or afterwards. See the chapter entitled Logging Sets for more information.
6.12 V Channels
Virtual or V channels provide a location for storing values that do not have any I/O associated with them. This can be results from analysis calculations, captured values from graphs, calculated expressions, or used as variables with a history. They are called channels because they can be used pretty much anywhere a channel is used within the DAQFactory program and typically have a history. Virtual channels are associated with a static connection name V. This Connection is referenced just like other connections, and can be made the default connection if desired. This means that typically you will have to put V. in front of any the name of your Virtual Channels when accessing them from the rest of DAQFactory, such as a screen component. To manually create a V channel, right click on the V: in the Workspace, or the CHANNELS: under the V: and select Add VChannel. Enter in the desired name of the new channel remembering the limitations on channel names. The name must start with a letter and can only contain letters, numbers, or the underscore. Click OK to create the V channel. To open the V channel view for the channel and edit its parameters, expand the CHANNELS: label by clicking on the + sign to the left of it, then click on the name of your new V channel. There is no V channel table like there is for channels. The V channel view has some similarities to the normal channel view. V channels have quick notes and notes just like regular channels. The views both have a graph displaying the data, and an available table for viewing data. There are three types of V channels:
Variable V channels:
A new V channel starts out as a variable V channel. Using the same methods you would use to set a real output channel, you can set the V channel to any value. The channel maintains a history of values and thus acts very much like a regular channel. Application: Use this type of V channel like you would a variable when you want to track historical values. If you do not need a history and just need to track a singular value, use a variable, as variables are faster to access.
Calculated V channels:
The next type is a calculated V channel. You can assign an expression to the channel, and the values in the V channel will be calculated from this expression every time the V channel is referenced. A variable V channel becomes a calculated V channel as soon as you enter an expression. Application: You can use calculated V channels to store complex calculations that you may use in multiple locations. Put the expression for the calculation in a V channel and then simply reference the V channel elsewhere in DAQFactory. This saves you from having to retype the expression multiple times. Application: It is perfectly legal to create constant expressions. For example, this expression will create a simple array: {3,4,7,1,3}. Use the InsertTime function to add time to a constant expression: InsertTime ({3,4,7,1,3},5h32m12,1). One example of this application is creating a lookup table of values.
148
Static V channels:
Static V channels are simply static arrays of data. The data can have time associated, or simply be data values. Captured values from graphs, and results from analysis calculations are stored in this type of V channel. Note: the data in both variable and static V channels is saved with your document along with the rest of the information about the V channel. The expression in a calculated V channel is of course saved as well.
Answer:
Depends. If you always want to use the average, then use the check box in the channel and enter the number of points to average. If you want to have the normal data and then display an average on the screen as well enter: Mean(MyChannel[0,9]) in the expression for the component to display the average of the last 10 points. You can also graph averages using either the boxcar or smooth functions depending on what you want.
Step 3: Click on CHANNELS: in the Workspace and then on MyChannelName under the CHANNELS: directory.
149
Step 4: Click on the Detail tab at the top of the page and use the drop down for Conversion to select
MyConversionName
Step 5: Click on the Table tab and verify that the data conversion is working. It will be a small number since the
original Test A to D value varied from 1 to 1.
Step 6: Repeat steps 3 through 5 with the MyOtherName channel. Once the conversion is applied, both channels
will show small numbers, but even though they both have the same conversion, they will show different data.
Answer:
This is normal. Calling this function manually adds a value directly to the history of the channel. Conversions are done on incoming data before they are inserted into the history. Your solution would be to apply the conversion manually to the value before the AddValue() function call. AddValue() will, however, cause the data point to be logged to any logging sets, broadcast to any remote systems, and alarms to be calculated
Answer:
The easiest way to do this is with a conversion that takes advantage of simple boolean math. Lets assume the threshold below which the channel should be set to 0 is 1.5. Create a conversion with the following expression and apply it to your channels: Value * (Value > 1.5) The trick here is that the boolean part of this expression, Value > 1.5, evaluates to either 1, if it is true, or 0 if it is false. So, if the value is greater than 1.5, we multiple our channel value times 1 which simply results in the original value. If the value is less than or equal to 1.5, then the boolean evaluates to 0, which when multiplied by our channel results in 0.
6 Channels and Conversions6.13 Questions, Answers and Examples6.13.2 Creating Conversions for input channels
VII
151
152
Once you have a component or components selected, you can move them by simply clicking and dragging inside the selection rectangle while holding the Ctrl key. The selection rectangle is the hatched rectangle that surrounds the selected component(s). Many components can be resized as well. When you select one of these components, the selection rectangle will have solid black handles at eight spots around the rectangle. You can click and drag any of these handles to resize the component. You can only resize one component at a time. If you have more than one component selected, the handles will not appear. If you have overlapping components, each subsequent click (with the Ctrl key pressed of course) on an overlapping area will select the next component in that area, making it easier to select components under other components. When you are trying to move a component that is entirely within the area of another component, you may have to click and drag the hatched area of the component instead of the center of the component, since clicking the center will select the other component. You can also use the keyboard to move, or even just nudge components around on the page. Just press the arrow keys while components are selected (no Ctrl key necessary) and the selected components will move one pixel in the desired direction. You can hold down the Shift key while pressing the arrow keys to move ten pixels at a time. For resizable components, you can use the arrow keys to resize as well, just hold down the Ctrl key while pressing the arrow keys to move the bottom right corner one pixel in the desired direction. You can hold down both the Shift and Ctrl keys to move the bottom right corner ten pixels at a time. When you have multiple components selected, you can use the tools in the Layout menu to quickly arrange your components. The Layout menu is available from the main menu. The tools in the Layout menu are also available by right clicking inside the selection rectangle.
Align: Aligns the designated edge of all the components to the component that was selected first among the block.
Does not change the size of the components.
Space Evenly: Arranges the components evenly along the designated axis within, approximately, the width or
height of the selection rectangle. Does not change the location of the components in the other axis.
Make Same Size: Makes the selected components the same size in the given axes based on the size of the
first component selected.
Order: Changes the Z order of the component. This affects which components get displayed in front of other
components. Note that since graphs and symbols are painted in the background, they are always displayed behind other components. So while moving a graph forward and back will cause it to be displayed in front of or behind other graphs and symbols, the graph will always be behind any other components. Think of it as two separate windows that you are looking through, one with all the graphs and symbols, which is always behind the other with all the other components.
Symbol: There are four options here that allow you to quickly rotate or flip a symbol component. This is
especially fast when using the keyboard shortcuts displayed next to the menu item. Rotation of bitmap images is not supported. DAQFactory supports the standard Windows clipboard for cut, copy and paste functions on components. You can use this to duplicate components, or move components on the same page, to another page, or even to another control document. For quick duplication, the Edit menu and the popup that appears when you right click inside the selection rectangle has a Duplicate Component menu item, which makes a copy of the component and pastes it onto the same Page, offset down the screen by 16 pixels. The Edit and popup menu also have a Change Component's Page option for moving a component to a different page (multiple pages are discussed in the next section). They also have a Delete Component menu item for permanently deleting the component.
153
Note: DAQFactory will always start with Edit mode turned off. Note: Edit mode does not stop the system from running, but simply changes the way the Ctrl key works. If you want to stop your system from running, use Safe Mode.
154
Enter the text to find, and the text to replace with and hit Replace All. DAQFactory will search through the component properties and replace all instances of the find text with the replace text. This only applies to string fields, so where it will change a caption or an expression it won't change a property like Font Size. You can find a replace on multiple components as well by simply selecting all the components to search through at once. This is most useful when you duplicate a group of components and you just need to change a channel name or array index in each component in the group.
155
The properties box for your new page will appear. Enter in a name for your new page and click OK. Click on your new page's name in the workspace to display it and you are ready to drop components onto it. You can switch among these pages using the keyboard or by clicking on the page name in the workspace. The page's property box is also available by right clicking on the desired page's name in the workspace and selecting Page Properties. There are only five properties available for pages:
Page Name: You can rename your page simply by typing your new page name in here. Page names have the
same criteria as other DAQFactory names: they must start with a letter and only contain letters, numbers, and the underscore.
Speed Key: Speed keys for pages work like they do for components. Enter in any key in this field, and when
you press that key the page will be displayed. You can enter more than one key per page and the same key on more than one page. This results in overlaid pages. One thing to note, though, is that the page view must have focus for speed keys to work. If you just clicked somewhere in the workspace or output, then that window will have focus and they will not process speed keys. To give the page view focus, simply click somewhere on the displayed page.
Refresh Rate: Your pages will not be redrawn the instant that a new data point arrives. The rate at which your
pages are redrawn is determined by the refresh rate. Typically a refresh rate of 0.5 second is sufficient. If you would like quicker response, you can drop this to quarter second or less. Faster (smaller) update intervals chew up large amounts of your processor time, though, so be careful. Dropping the update interval too far can actually result in a decrease in performance since your computer's processor doesn't have any room to perform the calculations it needs to in the time you desire. Pages are always redrawn from scratch with the latest data when you switch pages. If you are analyzing static data, you may wish to set your update interval to zero. This means the page will only redraw when you switch pages or when you do something during your analysis to cause a redraw such as rescaling a graph, adding a trace, or changing a component's properties. The minimum update interval is 30 milliseconds.
Background Color: This is the color the background is drawn in before any other components are drawn. Initial Page? If checked, this page is displayed when the document is first loaded. If multiple pages have this
property selected, the pages will be overlaid. In more advanced applications, some components offer actions to change the displayed page. This is especially appropriate for runtime touchscreen applications when a keyboard is not available and the workspace is not visible.
156
ClosePopup() function. For example, create a Close button on your page. If you don't and you display a modal popup you will be stuck with that popup and unable to do anything else with DAQFactory. Top, Left, Bottom, and Right define the screen location of the popup. If any of these values are negative or not included, the popup is autosized and centered on the screen. Make sure if you have the No Close flag set that you do not make your popup too small and end up hiding your component that closes the window. While you can have multiple popups at once, a particular page can only be displayed as a popup one at a time. In other words: Page.PasswordEntry.PopupModal() Page.PasswordEntry.PopupModeless() will only popup PasswordEntry once as a modal window. The second line will be ignored. However, if you wish to move a popup that is already displayed, or change the No Close state of the popup, you can simply call popup again with new parameters. Note that calling PopupModal() or PopupModeless with no position parameters on a popup that is already displayed will not autosize the displayed popup. Application: The modal popup is very useful for requesting information from the user. The popup must be closed before any other part of DAQFactory can be accessed. For example, if we want to create a system where a user must provide a password to access certain pages: 1. Create a page that requests the password using the edit box component and whatever other components, such as panel and text components to make it look nice. Call the page "PasswordEntry". Store the result of the password entry into a variable, say Var.strPassword. 2. Add a button to the page labeled Enter. Assign a quick sequence action to the button: if (Var.strPassword == "ThePassword") Page.PasswordEntry.ClosePopup() Page.CurrentPage = "NewPage" else System.MessageBox("Invalid Password!") endif 3. Create a page called "Main" with a welcome screen and a button labeled Login. Assign a quick sequence action to the button (or use the PopupModal action): Page.PasswordEntry.PopupModal() 4. Clear out the Speed Keys for all your pages. You now can put things on NewPage that can only be accessed by entering ThePassword into the PasswordEntry page. Application: The modeless popup is very useful for displaying important data that you want to be able to view at any time. This window floats on top of DAQFactory while still allowing you to work with the rest of DAQFactory. This could also be used to allow DAQFactory to spread across multiple monitors. Windows considers 0,0 to be the top left corner of the main application screen. Depending on how you have your screens arranged, the coordinates will be in reference to that point. So, if your second screen is to the left of your main screen, the x coordinates will be negative.
157
labelled "Load in Full Screen", then save your document, or alternatively, use the -F startup flag as described in the startup flag section.
158
At the top is a drop down list of the current languages in this document. To start, you'll need to click the Add button to add a new language. You will be prompted for the language name. This must be unique among languages, but is otherwise not subject to the normal limitations of DAQFactory names. Once you have added a language you can start adding phrases. Phrases are the strings in the default language you placed in the various components and script in your application. Phrases do not include the opening "@" which is implied. To add a phrase, type in the phrase in the box to the right, and then the translation of that phrase in the currently selected language. Then hit Add to add the phrase to the list. Continue as needed. To delete a phrase, select it and hit the Del key. There are several features to make things easier. You may find it easier to keep a spreadsheet of all the phrases you use in your document. If so, you can import and export from comma delimited (CSV) files a complete language phrase list. The CSV file should contain two columns, the phrase and the translation. The first row in the file should be a header and is ignored by the import routine. The best way to ensure that your file is in the correct format is to export a small language file and then add your phrases to this file using a program like Excel. If using Excel or another program that supports all the features of a CSV file, then you should be able to use carriage returns, commas, and quotes within your phrases and translations. DAQFactory supports the proper escaping of these characters in the standard CSV format. If using Excel, simply save your worksheet as a .csv file and Excel will do the rest. Once you have created one language, instead of hitting Add to add a new language, you can press Copy to add a new language with an exact copy of the currently selected language. You can then go through and edit the phrases of the new language as needed. Languages are saved with your document. When you start DAQFactory and load your document, DAQFactory will use the phrase specified in the components and strings (without the @) until you specify a different language. To specify the working language use the system.language variable: System.Language = "Klingon" This setting is not case sensitive. The change will occur immediately with the next screen refresh. To reset back to the default phrases, simply specify a language that does not exist in this document. There is also a function to list 2011 AzeoTech, Inc.
159
System.GetLanguageList(): returns a string array with all the languages in this document.
This function could be used to populate a combobox to allow the user to select their language at runtime. Then, if you added a language to your document, this combobox would automatically update. Note: the @ marker only applies if it appears as the first character in a string. If it appears elsewhere in the string, it will appear as a normal @ sign. If you actually want a @ as the first character of a string, simply put two @'s. Note: the tree list component does not translate. The component must be pre-populated with translated strings. This means that if you change the language and want the tree list to update, you will have to clear the tree list and repopulate it. If you use strings marked for translation in a routine that populates the tree list, this should be easy.
Variables: Page.strCurrentPage:
Sets or retrieves the currently displayed page. This is a string. Page.strCurrentPage = "Page_2"
160
are over a graph, in which case the graph coordinates are displayed. Cropping in this way overrides any width/ height values provided in the function call. Only supported in versions that support the networking.
Page.PrintPage(name):
Prints the given page. Will switch to the page first and then print it.
Page.PrintSetup():
Displays the standard windows print setup window
Page.UpdateEdits():
This function causes all the edit and combo box components to replace their contents with the current value for their Set To Channel, basically displaying what the current value is. This applies to all pages.
Individual pages also have variables and functions. They are accessed by entering "Page.PageName." where PageName is the name of the desired page you'd like to work with.
Variables: Page.PageName.Interval:
Sets or retrieves the refresh rate of the page
Page.PageName.strSpeedKey:
Sets or retrieves the speed key associated with the page
Page.PageName.BackColor:
Sets or retrieves the background color of the page
Functions: Page.PageName.ClosePopup():
Closes the popup for the given page.
Page.PageName.PopupModal():
Displays the given page in a modal popup window. A modal popup window displays on top of DAQFactory and must be closed before the user can work with any other part of DAQFactory. This is most useful for requesting information from the user.
Page.PageName.PopupModeless():
Displays the given page in a modeless popup window. A modeless popup window floats with the DAQFactory window and can stay open while the user works with other parts of DAQFactory. This is useful for displaying important data and keeping it visible even when you switch to other views. 2011 AzeoTech, Inc.
161
Note: only one popup can exist at one time for each page in your document.
Page.PageName.UpdateEdits():
This function causes all the edit and combo box components to replace their contents with the current value for their Set To Channel, basically displaying what the current value is. Unlike Page.UpdateEdits(), this function only applies to components on the given page.
Type])
7 Pages and Components7.14 Page Functions
162
CreateStringProperty(Name, Initial Value, [Group = "Misc"], [Description = ""], [Edit Type = "string"], [Options], [OptionData]): these two functions create a user property
for the component. The only difference is the data type of the resulting property, number or string. A user property is a property that like the built in ones, will persist inside the DAQFactory .ctl document, so will be saved when you do File - Save (or call System.SaveDocument()). The property acts just like a local variable with the exception of the persistence and the ability to edit the property from the Properties control bar. Name must be a valid variable name. Initial Value is the value assigned to the property when it is first created. Once the property is saved with the document, the initial value, and for that matter, this whole function call, is ignored, as the document loading will create the variable and initialize it. Group determines which group the property will appear under in the Properties control bar. Description is currently unused, but in the future will offer a description of the property in the Properties control bar. Edit Type is one of the following strings and determines what sort of editor will be presented to the user in the Properties bar: "color" - a color "double" - any floating point value "integer" - any integer "pinteger" - a positive integer "pzinteger" - a positive or 0 integer "string" - a string "bool" - true or false "date" - date only "time" - time of day only "datetime" - date and time "font" - a font from the system. A drop down list is presented. Returns a string with the name of the font. "file" - a file path. A button with an ellipses is presented that opens a file selection window. "options" - allows you to specify a list of options that the user can select from. The options should be a semicolon list as the Options parameter of the CreateProperty() function. You can also optionally present a semicolon list of data to be returned when the corresponding option is selected. If you do not specify the OptionData, the selected Option itself is returned.
MoveBy(OffsetX, OffsetY): this moves the component by the given pixel offsets in the X and Y
directions. X is left and right with + values going to the right. Y is up and down, with + values going down. The size of the component is not changed. MoveTo(X, Y): this moves the component to a particular location on the screen without changing its size. 0,0 is the top left corner of the page. Position: this is an array of 4 values (either a 1 dimensional array of 4 values, or a 2 x 2 array) in the order left, top, right, bottom and define the position of the component on the screen. Some components ignore the bottom and right coordinates. PositionLeft, PositionRight, PositionTop, PositionBottom: these determine the position of the component on the screen as well and exist mostly for backwards compatibility, but can also be used to easily change just one of the position coordinates. Some component ignore the bottom and right coordinates. strSpeedKey The following three functions are identical to their global counterparts described in the sequence chapter, except they run in the locale of the component and will automatically terminate if the component is deleted:
Properties:
163
Components of course have their own predefined properties like BackColor, strText, etc. Each component type has their own set. You can add additional properties to be used by your components scripts, editable from the properties window, and persisting to the document file. These are just like local variables, except they persist to file. To create a new property, use the CreateProperty() and CreateStringProperty() functions described in the last section in detail. Of course you can also have just regular local variables by declaring them as such, but these variables won't persist to disk unless you manually do so. The most common place to put your CreateProperty() calls and local declarations is in the OnLoad() event.
Events:
There are a number of predefined events that get called at various times. These events can have sequence script to perform special actions. The script runs in the context of the component (meaning, for example, that you can access the properties of the component without putting component.myname. in front). To edit the events, use the Event/ Function docking window. If it isn't visible, or tabbed along the right side, select View-Event/Function from the main menu. The Events available are:
OnContextMenu: called when the user right clicks on the component. The parameter "Loc" is passed in which
contains the x/y coordinate where the click occurred relative to the top left corner of the component. Loc[0][0] contains x, loc[0][1] contains y.
OnLButtonDblClk: called when the user double clicks on the component. Like OnContextMenu, loc is passed
in.
OnLButtonDown: called when the user clicks down on the mouse on the component. Like OnContextMenu, loc
is passed in.
OnLButtonUp: called when the user releases the mouse on the component. Like OnContextMenu, loc is passed
in.
OnLoad: called when the component is created or loaded from disk. This is the best place to put local
declarations and CreateProperty() function calls.
OnMessage: this function is called when a message that this component is listening for is received. To listen for
a particular message, use the AddListener function described in the last section. When a known message is received, this event passes in strMessage containing the message name, as well as Param1 and Param2, containing the parameters passed when the message was sent. To actually send a message use the SendMessage() function. This function has the prototype: SendMessage(Message, Param1, Param2). The message will be sent to all listening components. This function is of global scope.
OnMouseMove: called when the user moves the mouse pointer over the component. Like OnContextMenu, loc
is passed in.
OnPaint: called before the component is painted to the screen. This is a good place to adjust standard properties
like background color or text before the component is drawn. There is no facility to draw from this event. If you want to do scripted drawing, use the Canvas component. If you use the OnMouseMove event, make sure it is quite fast, otherwise the mouse will become sluggish when you move it over the component. Really, all the event code must be fast as it runs in the primary thread of the application and would cause DAQFactory to appear sluggish.
Functions:
In addition to events, you can create your own member functions. These functions are local to the component and can be called from any other member function or event. They are public, so they can also be called using Component.MyComponent. notation from anywhere else in DAQFactory if you named your component. To add a new function, select the component and in the Event / Function window, click on the Add button. You will be prompted for the function name. Once you click OK, you will see your new function in the Event drop down and you can enter script in the area below. If you decide you don't need the function anymore, select it from the drop down and hit the Del button.
164
165
clear the history leaving any number of values. Display Alarms: When clicked, the view will switch to the alarm summary view displaying the status of all the alarms on the given connection. If you are not doing any networking, select Local for the connection. Change Page: When clicked, the currently displayed page is changed to the given page(s). Multiple pages can be overlayed by listing multiple pages with the action. Popup Page Modal: When clicked, the given page is displayed in a separate popup window. The window is on top of all other DAQFactory windows and must be closed before the rest of the DAQFactory windows can be accessed. This window is useful for requesting information from the user. Popup Page Modeless: When clicked, the given page is displayed in a separate popup window. The window is a floating window. The rest of DAQFactory can be accessed while this window is displayed. This window is useful for displaying information that you would like to keep visible at all times. Close Popup: When clicked, the given page's popup is closed. Print Page: When clicked, the given pages are printed. If multiple pages are specified, the pages are overlayed before printing. Print Preview Page: When clicked, the given pages are displayed in a print preview window. If multiple pages are specified, the pages are overlayed before previewing. Print settings: When clicked, the standard windows Print Setup window is displayed. Exit: When clicked, DAQFactory will stop all acquisition and terminate. You can assign multiple actions to a single component. Simply click on the Add button to add more actions, or Delete to delete an action. Use the up/down arrows to select which action you would like to edit. In general you may find it easier to simply use a Quick Sequence and sequence code to perform multiple actions as most of the actions available are accessible through sequence code. The exceptions would be Submit and Display Alarms.
The text component displays a text label. The label can be a single line or multiple lines. The text is clipped to the size of the component, so you may need to resize the component to display multiple lines. Words will be wrapped to the size of the component as well. If the background color is set at pure white, the background is left transparent. This component can be setup to perform an action when clicked. Application: The obvious use of the text component is for labels, but the text component can also be used to provide longer explanations. The word wrap makes this easy. Component Variables and Functions (advanced): please see the section on Component Names for a description on how to use these. strAlignment: this contains a string and should be either "left", "right" or "center" (case sensitive) BackColor strBlink: this contains an expression that if evaluates to true causes the component to blink. This is not available from the properties window and is only available programmatically. strFontName ForeColor strText strVisible: this contains an expression that if evaluates to false causes the component to not display. If the expression is blank, then the component will display. This is not available from the properties window and is only available programmatically. strXSize: this is the same as the font size, but can be an expression similar to the Variable Value component. XSizeMax: this constrains the XSize. This is not available from the properties window and is only available programmatically.
166
XSizeMin: this constrains the XSize. This is not available from the properties window and is only available programmatically.
The panel displays a simple block of color with an optional edge. You can also assign an action if the user clicks on the panel. The panel will draw behind most other components no matter what the order. Application: Use the panel component to group other components on a page. Component Variables and Functions (advanced): please see the section on Component Names for a description on how to use these. BackColor DrawEdge RaisedEdge
7.18.2 Displays
7.18.2.1 Variable Value Component
The variable value component will display your data in simple numeric form. Like most components it can display a single channel or the result of a complex calculation. This component can also display an array of values as well. The variable value component's property box has four sheets in it. The last three are common to the variable value, descriptive text and symbol components and are discussed a little later. The first sheet, the Main sheet is unique to this component. Here is a list of the fields on this sheet and their function:
Caption: This is the text that is displayed in front of the numeric value. A colon is placed between the caption and
the value automatically, unless no caption is specified.
Expression: Enter the formula you would like to evaluate. This can be as simple as a single channel, or more
complex formula. The result can either be a single dimensional value, or a two dimensional array, in which case only the first 20 values will be displayed.
Units: This is the text that is displayed after the numeric value. Precision: Specifies the number of digits after the decimal point that will be displayed. Font: Select the desired font for the display. Font Size: This specifies the size, in points, of the font used to display the value. This will be overridden by any
expression that changes the size of the display (see the size property page).
Speed Key: Because a mouse can sometimes be difficult to control, especially on a bumpy plane or ship, or
when you need to quickly toggle an output or the like, DAQFactory provides speed keys. You can assign a speed key, which can be any character you can generate with the keyboard, to any component, and when you press that key and the page that the component is on is visible on the screen, the component will automatically be selected. Once the component is selected, you can quickly change an output value by pressing the space bar, or open the properties box by pressing the enter key. If you assign the same key to more than one component and they are on pages that are not displayed at the same time, then only the component being displayed will be selected. If you assign the same key to more than one component on the same page, or pages that are overlaid, then all the components with that key will be selected. If you assign a speed key to a component that is also used by a page, then the component speed key will take priority over the page speed key when the component is on a page being displayed. You can assign multiple keys to a single component. pressing of those keys will select the component. Just list the keys right after each other (i.e. ABC). Then
167
The page view must have focus for speed keys to work. If you just clicked somewhere in the workspace or output, then that window will have focus and they will not process speed keys. To give the page view focus, simply click somewhere on the displayed page, or select Quick - Goto Page View from the main menu.
Quick - Analog Out: Pressing this button will automatically set up the parameters for this component to
trigger an analog output or command channel. When you press the button, a dialog box will appear allowing you to select which output channel you would like assigned to this component. Simply select the desired channel, and DAQFactory will do the rest. You may want to adjust some of the settings, such as the caption, afterwards. This button only really works well with a newly created component as it only sets the minimal amount of settings, and does not reset other properties.
Quick - Average: Pressing this button automatically generates an expression to display a ten second average
of a channel. When you press the button, a dialog box will appear allowing you to select your desired Channel. Once complete, you can make the average time longer by changing the 9 in the expression to your desired length minus one. Again, this button works best on a newly created component. Application: The variable value component can be used to display both numeric as well as string data. Of course with string data, the precision property is not used. Component Variables and Functions (advanced): please see the section on Component Names for a description on how to use these. BackColor: this will reset the table of colors to a single background color. strBlink strCaption DisplayOutline strExpression strFontName ForeColor: this will reset the table of colors to a single foreground color. Precision strUnits strVisible strXSize XSizeMax XSizeMin
The descriptive text component is very similar to the variable value component, except that after the expression is evaluated, the result is compared to a table of text labels to determine which gets displayed. No numbers are displayed, only labels. This is most useful for digital signals that only have two values, for example On / Off , Open / Closed, etc. The descriptive text component can also be used to display simple text labels, which is what is displayed when a descriptive text component is first created, but the static - text component is probably better for this use. To have the descriptive text component change with the result of the expression requires an expression and the entry of the various labels in the text table. The expression typically should evaluate to a one dimensional value, but will be converted to a one dimensional value if necessary. The text table works like all the other tables in DAQFactory. Click on the Add button to add new rows, the Delete button to remove rows, and double click on a cell to edit its contents. The table contains two columns, the threshold and text label. The threshold of each row indicates the highest evaluated value that will result in the given text label being displayed. If the evaluated value is above the highest threshold in the table, the text label of the highest threshold is used. An example of the table will explain this concept better:
168
The text component with this table would display the word Low for all values up to and including 1.00, Medium for all values up to and including 5.00, and High for all values above 5.00. You could have as many or few rows as necessary. Note that the table is automatically sorted by threshold within DAQFactory, so you do not have to worry about the order of the rows. Most of the rest of the fields in the text component's main property sheet are the same as display value's property sheet and we refer you there. Here is a description of the quick buttons which have different functions with text components:
Quick - Digital In: Pressing this button automatically creates an expression and text table for displaying Dig In
type On / Off values. The text is automatically set to ON / Off for a value of 1 and 0, and is set to display the ON in green and Off in red.
Quick - Digital Out: Pressing this button does the same as the Quick - Digital In except it also sets up the
component to toggle the output value of the channel when the component is clicked.
Quick - Sequence Trig: This button creates a component that will start and stop a sequence when clicked
and display either RUNNING or Stopped in green or red depending on the current status of the sequence.
Quick - PID Loop Trig: This button creates a component that will start and stop a PID loop when clicked and
display either RUNNING or Stopped in green or red depending on the current status of the loop. Application: The typical uses for this component is for controlling digital outputs, and starting and stopping sequences, PID loops, export and logging sets. But as shown in the example above, this component can also be used to display values in more fuzzy terms like Low, Medium and High. Component Variables and Functions (advanced): please see the section on Component Names for a description on how to use these. BackColor: this will reset the table of colors to a single background color. strBlink strCaption DisplayOutline strExpression strFontName ForeColor: this will reset the table of colors to a single foreground color. strText: this will reset the table of text values to a single text strVisible strXSize XSizeMax XSizeMin
Adding symbols to your pages is as simple as pasting them where you would like them. We've even provided a library of over 3800 symbols that you can use in your projects. You can open this library by selecting Tools - Symbol
169
Factory. This will open the symbol factory browser application which is an easy to use product for viewing all the symbols. You can flip or rotate the symbols, change the coloring, and even import your own symbols into the library. To get a symbol out of symbol factory and into DAQFactory, simply press the Copy button in Symbol Factory to copy the currently selected symbol onto the Windows clipboard, then right click on your page in DAQFactory and select Paste. You can actually put any symbol that can be converted to either a WMF or bitmap format into DAQFactory by simply copying it out of another application and pasting it into DAQFactory. You can also put symbols into DAQFactory using the drag and drop method. From the Symbol Factory, simply click on a symbol and drag the symbol onto the Control Page. The cursor will change when you are over the page. Release the mouse where you want the symbol dropped. This method is very quick for placing multiple symbols from Symbol Factory. When you paste or drop a symbol directly onto a page in DAQFactory, you are simply creating a symbol component and pasting the symbol into the component. The symbol component provides many more features, some of which have been discussed already. You can select any symbol you have pasted onto a page, or create a new symbol component, and open the properties box for the symbol component to change these features. In addition to a static symbol that does not change, symbol components can display different symbols depending on the result of an expression, or even animate symbols. On the main sheet of the symbol component's property box is where the expression and symbols are entered. The system for selecting which symbol gets displayed works very similar to the text component and its selection of a text label. Like the text table, use the Add and Delete buttons to add or remove rows from the table. Enter a threshold value in the same way that you would in the text table. To insert a symbol in the symbol cell you must have a symbol on the clipboard. By double clicking on the symbol cell, the symbol from the clipboard will be pasted into the cell. Once pasted, you can adjust the symbol by setting the rotation, HFlip and VFlip columns. The symbol table has some additional features for animation. The Rotate column allows you to rotate the desired symbol when it is displayed (as determined by the threshold). The Rotate column determines the amount the symbol is rotated, in degrees, each time the page is redrawn. Bitmap images cannot be rotated. To make an animation, simply create a separate row for each symbol in the animation and assign the same threshold to all the symbols. The order column determines the order in which the symbols are displayed in the animation. If you don't care about the order, just leave the column blank. Note: As soon as you add more than one symbol to a symbol component, you must have an expression specified to determine which image to display. For a simple animation where the threshold is the same, simply put that threshold value as the expression. By default, the threshold is 0. If this is left as is, you can simply put 0 in the expression. Note: Bitmap symbols cannot be rotated from within DAQFactory. They can however, be flipped. Symbol components also have an additional property sheet called Location. This sheet allows you to enter expressions that will change the position and rotation of the symbol on the screen. All three options, X Location, Y Location, and Rotation, work the same. Enter an expression, that when evaluated will be used as either an offset in the X or Y axis in pixels from the original location of the symbol, or a rotation, in degrees, relative to the original orientation of the symbol. The range parameters will constrain the total change in position and rotation. If you need to select a symbol that is moving, or is no longer at its initial position because of these features, you must click on its original location, not on the current location of the symbol. This way you don't have to chase down any fast moving symbols! If you don't want this, and need to be able to move a symbol and click on its location as displayed, use the Position variables of the component to move it around. Note: While symbols are supported in all versions of DAQFactory, the Symbol Factory is not. You can create your own symbols in other applications, but you will not have access to the symbols in the symbol factory without the appropriate DAQFactory version. Symbol components containing metafile symbols can also be partially filled with solid colors based on an expression. This is a great way to do a cutaway tank animation, but can be used on other symbols as well. Most of the symbols included in the Symbol Factory can be filled this way. Bitmap symbols cannot be partially filled. By default, symbols are displayed in their native colors. To fill a symbol with partial colors, select the Split Colors tab from the Symbol component's properties and enter a valid expression that determines how much to fill the symbol. The result of the expression is compared against the Scaling factors specified on this page to determine what percentage of the symbol is filled with what color. The two colors can also be specified here. So, if your expression evaluated to 70 and the scaling was 0 to 100, then 70% of the component would be filled in the Active Color, while the other 30% would be filled in the Inactive Color. By default, the bottom 70% would be filled with the Active Color, but you can
170
flip this by selecting Reverse, or run it horizontally instead of vertically by checking Horizontal. Component Variables and Functions (advanced): please see the section on Component Names for a description on how to use these. LoadJPEG(path name): this function will replace any existing symbols in the component with a jpeg file loaded from disk. BackColor: this will reset the table of colors to a single background color. strBlink strExpression OutlineColor: this will reset the table of colors to a single outline color. strRotation RotationMax RotationMin SplitColorActive SplitColorInactive strSplitExpression SplitHoriz SplitMaxScale SplitMinScale SplitReverse strVisible strXLoc XLocMax XLocMin strXSize XSizeMax XSizeMin strYLoc YLocMax YLocMin strYSize YSizeMax YSizeMin
You can change a descriptive text or variable value component's foreground and background colors. You can even have the foreground or background color change with the value being displayed. The same is true for symbol components, but since symbols already have foreground coloring, you can create a box around the image and change the box's color instead. To change the component's color, open the component's property box and select the Color sheet. The color sheet contains two tables, one for foreground color and one for background color. For image components, the foreground color table is replaced with an outline color table. If you only want to display your component in a single color that doesn't change with the value, press the Quick Color button under the desired table to quickly set a single color. If you would like to create an outline around a text or value Component, click on the outline checkbox above the background color table. To have the fore or background color change with the result of the main expression, you will need to add more rows to the desired table(s). These tables work very similar to the text table on the main page of the descriptive text component. Please see this section for a description of how thresholding works. To select a color for a row in a table, either double click on the color currently displayed in the desired row, or move the cursor to that cell and press the space bar. A color selection dialog will appear allowing you to select your desired color. The difference between color tables and the text table is that colors can be crossfaded. The following sample table will demonstrate this:
171
If the value of the main expression is less than 0 then the color will be red. As the value approaches 10, the color will cross fade from red to green. The color will remain solid green up to 100, then will cross fade from green to blue as the value approaches 1000. Above 1000, the color will be solid blue. The default foreground color for text and value components is black. If nothing is entered in the foreground color table, black will be used. The default background color for text, value, and symbol components, and outline color for symbol components is transparent. If nothing is entered in the background color table, no background is painted, and the component will appear transparent. If pure white (RGB value 255,255,255) is used in the color table, then again the background will appear transparent. To paint a white background, use an off-white (for example RGB 255,255,254).
For variable value, descriptive text, and symbol components, you can enter an expression that, when evaluated, will determine the size of the component, if the component is visible, or whether the component should blink to get the users attention. All these are available from the Size sheet of the component's properties box.
Size: For descriptive text and variable value components, only the X Size fields will be available. This is because
the result of the size affects the total font size in both axes. If you enter in an expression for the X size field, then the result of the expression will be used to determine the font size in points. This will override the value entered on the main sheet. You can limit the possible values by setting the minimum and maximum point size in the range fields. For symbol components, both the X and Y size can be adjusted independently. The result of each expression determines the size, in pixels, along the given axis with the constraints given. If an expression is not provided for an axis, then the size of the component as originally drawn is used.
Visible: If a visible expression exists and the result is zero, then the component will not be displayed. Any nonzero result and the component will be visible (the default). Note that once the component is invisible, it may be hard to find to adjust any parameters!
Blink: If a blink expression exists and the result is non-zero, then the component will flash between visible and
7 Pages and Components7.18 The Components7.18.2 Displays7.18.2.4 The Color Property Page
172
nonvisible. The flash rate is determined by the update interval of the page it is on.
The table component will display multiple values in column format similar to the tables used within DAQFactory for adding channels, conversions and the like. Each column in the table will display the result of an expression. In the properties for the table component is a table for specifying the details of each column in the component. Each row in the properties table corresponds to a column in the component. The order of columns is determined by the order of the rows in the properties table. You can move rows up and down by selecting the row and clicking either Move Up or Move Down.
Expression: the result of the expression determines what will be displayed in the column. The result can be
either an array of numbers or strings.
Title: the title displayed at the top of the column. You can optionally turn of title display using the Display Titles?
option described below.
Width: the width of the column in pixels. Prec: the precision of the numbers displayed in the column. This is ignored if the expression results in string data. Align: the alignment of the data within the cell. This can be left, right, or center. The title is aligned accordingly. F Color: the foreground color of the text displayed. B Color: the background color of the column. Row Height: the height of each row. The columns will word wrap if the row height is large enough to allow
multiple lines of text per row.
Show Grid: if checked, a grid is drawn around each cell in the table. Grid Color: the color of the grid, if drawn. Font: the font used to display all the text in the table. Font Size: the font size in points used to display all the text in the table. Ellipsis?: if checked, then an ellipsis (...) is displayed at the end of any text that does not fit inside its cell in the
table.
Display Titles?: if checked, then a row is displayed with the titles for each column. Title Fore Color: the color of the text used to display the titles. Title Back Color: the color of the background of the title row. Speed Key: a key that when pressed will select this component.
Component Variables and Functions (advanced): please see the section on Component Names for a description on how to use these. AddColumn(expression, [title], [width], [precision], [alignment], [color], [bkcolor]): Adds a column to the table with the given parameters. Only the expression parameter is required. Alignment should be "left", "right" or "center". To create a new table dynamically, call ClearColumns() then AddColumn() for each column in your new table. ClearColumns(): this function will clear all the columns, emptying the table. Typically you will use this before the AddColumn() function to create a table dynamically. DisplayEllipsis DisplayTitles strFontName 2011 AzeoTech, Inc.
173
The canvas component allows you to use sequence type scripting to draw on an area of the screen. This is useful for doing complex animations and other types of drawings that might not be available using the other DAQFactory components. This is an advanced component and should only be used by those experienced with DAQFactory scripting. The canvas component executes sequence script every time it is to be drawn. From within the sequence you can call a variety of drawing functions to actually draw to the canvas. Because all the drawing is handled by the sequence script, the script is the only property of the canvas component. Two arguments are passed to the sequence each time the canvas component is to draw itself. The first, DC, is the device context. It is not terribly important to understand the purpose of this argument, but it is required for all the drawing functions. When you call any of the drawing functions, you should pass the DC argument. If you pass an invalid DC, nothing will happen. The other argument is Position. This is a 2x2 array with the top left and bottom right coordinates of the component. For example, {{10,20},{80,90}}. Within the canvas component's sequence, you can perform any of the normal sequence functions. In addition to these, a number of other functions are available designed especially for drawing to the screen. Before delving into them, a note about coordinates. Pretty much all the drawing functions use screen coordinate pairs. Each pair consists of an X value and a Y value. The X value is the coordinate across the screen from the left side of the page. The Y value is the coordinate down the screen starting at the top of the page. In general the X,Y pair should be along the second dimension of the array. In other words, {{x,y}} and not {x,y}. Some functions will accept {x,y}, but we recommend against it. The reason for putting each {x,y} pair in the second dimension is to allow you to create an array of coordinates. Most drawing consists of polygons which a group of lines running between coordinate pairs. So, {{10,10},{100,10},{100,100},{10,100}} would define a square. All the canvas component functions used for drawing start with Draw.. Please see the end for an example code. One of the most important functions you will use with the canvas component is not for drawing at all, but rather for processing coordinates. Lets say you have the coordinate array that defines the square, {{10,10},{-10,10},{-10,10},{10,-10}}, and you wish to rotate it, make it twice the size and offset it to the location of the component. To do so requires some rather basic matrix math. Fortunately, DAQFactory isolates you from even this with the Transform() function:
Transform(Coord array {{x,y},{x,y}...}, offset {{dx,dy}}, scale {{x,y}}, rotation (deg)): This function takes a coordinate array, for example our square, and will offset, scale and/or rotate them,
returning the new coordinate array. The rotation is done around the {{0,0}} location. So: Private Shape = {{10,10},{-10,10},{-10,-10},{10,-10}} TShape = Draw.Transform(Shape,{{10,10}},2,45) results in {{38.284,10},{10,38.284},{-18.284,10}, {10,-18.284}}
Offset(Coord array, offset): This is simply a simpler version of the Transform function with scaling set to 1
and rotation set to 0. Use this to move your drawing to position of the component if you aren't doing any other transformations: Private Shape = {{10,10},{-10,10},{-10,-10},{10,-10}} TShape = Draw.Offset(Shape,Position[0]) Position is a 2x2 array. Position[0] has the x,y coordinate pair of the top left corner of the component, while Position [1] has the bottom right coordinate. Unlike most of the rest of the functions described here, the above two functions can be called from anywhere in DAQFactory and not just in the Canvas Component sequence. Once you have the proper coordinates, you can then use one of the following functions to actually draw. Note that all these functions take the DC argument provided when the sequence is called.
174
Clip(DC, Rectangular coord array): This is the same as ClipRgn, except it clips to a rectangle. Like
ClipRgn(), you must clear the clipping by passing 0 for the coordinate array.
ClipRgn(DC, Coord array): This will limit all future drawing commands to the shape provided by the
coordinate array. To clear out the clipping region, simply set Coord array to 0: Draw.ClipRgn(DC, 0). Make sure to clear the clipping region before your sequence ends. Unless you are clearing the clipping region, Coord array must have three coordinate pairs.
FillEllipse(DC, Rectangular coord array): This will fill an ellipse or circle that just fits inside the
rectangle formed by the coordinate array provided. The current brush is used to fill the ellipse.
FillPolygon(DC, Coord array): This will fill a polygon given by the coordinate array with the current brush
color. Use SetBrush() to adjust the brush color. Use FramePolygon() to draw a border.
FillRect(DC, Rectangular coord array): This is similar to FillPolygon() except designed for rectangles. FrameEllipse(DC, Rectangular coord array): This will draw an ellipse or circle using the current pen
that just fits inside the rectangle formed by the coordinate array provided.
FramePolygon(DC, Coord array, offset): This works just like PolyLine(), except a line is also drawn
from the last coordinate in the array to the first, closing the shape.
FrameRect(DC, Rectangular coord array): This is similar to FramePolygon() except designed for
rectangles.
GetTextExtent(DC, Text): returns the size of the given string in pixels if it were plotted with the current
font. Use this for centering or other text manipulation.
Image(DC, Data {{x11,x12,x13},{x21,x22,x23},{x31,x32,x33},...}, Position, Scale, Colors, Thresholds): This will draw an image much like the Image component. Data should be in the same
format. Position determines the top left corner. Scale determines the size in pixels of a unit of data. Colors and Threshold are arrays that determine the color range exactly like the Image Component.
LinearLegend(DC, Rectangular coord array, Colors, Thresholds, Precision): This will draw
a linear legend with the legend colors stacked on top of each other. The coordinate array determines where the legend is displayed. Colors is an array of color values for each item in the legend. This is matched up with Thresholds, which is an equal sized array of numbers that label the colors. Precision determines how many figures past the decimal point are displayed when labelling. You could of course create your own legend using the other drawing functions, but this is much faster.
LineTo(DC, Point): This will move the current pen position to the given Point drawing a line from the previous
point. Use SetPen() to change how the line is drawn.
MoveTo(DC, Point): This will move the current pen position to the given Point. Use in combination with
LineTo() to create line drawings.
PolyLine(DC, Coord array): This will draw line segments between the coordinates provided using the
current pen. Unlike FramePolygon(), this function does not connect a line between the last coordinate and first coordinate, closing the shape.
TextOut(DC, Point, String): This will output the given string using Point as the top left corner of the text.
You can change the text color and font using the SetTextColor() and SetFont() functions. For performance reasons you should use the rectangular versions of the above functions instead of the polygon versions if you are drawing rectangles. Likewise, Polyline() will be much faster than a series of LineTo() calls. The following functions set the current pen, brush, font, and text color. They can be called from anywhere in DAQFactory.
SetBrush(Color): This sets the current brush color and therefore the color used for all the fill drawing
functions.
175
SetFont(Style, [Height], [Bold], [Italic], [Underline]): This sets the font that TextOut() will use
to draw the text. Only the Style parameter is required. Style is the name of the font. The font must exist in your system. Height is the height of the font in pixels (default is 16). Bold, Italic, and Underline should be 1 or 0 to enable the given characteristic (default is none). If you do not use SetFont(), TextOut will use Arial 16 pixels in bold.
SetPen(Color, Width, Style): This will set the current pen for any function drawing a line. The color is the
RGB color, width is the width in pixels. Style is a string and can be one of the following: solid, dash, dot, dashdot, dashdotdot, null, insideframe.
SetTextColor(Color): This sets the color that TextOut() will use to draw the text. The background is always
transparent. Note: because the component may be drawn often, make sure the canvas component's sequence is as short and fast as possible. Do not use any delay(), wait(), or similar functions inside the sequence. Very Advanced: For those who are MFC programmers, the DC parameter is simply a pointer to an MFC 6.0 CPaintDC object. Provided you create an extension DLL so object pointers can be passed, you can create your own drawing routines in C for use in the canvas component. Just type cast the DC parameter back to a CPaintDC pointer. Use the extern() function to make your routines accessible from DAQFactory. Note, however, that you will have no way of verifying the DC parameter is valid. Here is a sample that creates a rotating compass rose similar to the dual compass component. This is basically a circle with ticks every 5 degrees and labels every 30 degrees that rotates based on a variable. You can simply drop a Canvas component onto a page, and paste this code into the components property window and you will see it draw and rotate with every screen refresh: // the next three lines just make the dial rotate 1 degree every refresh. global rot = 0 rot += 10 rot = rot % 360 // the coords for a tick (at 0 degrees) {x,y} private tick = {{0,0},{10,0}} // the coordinate of the 0 degree text assuming 0 radius circle private textloc = {{30,0}} // force location to a circle even if user has dragged a rectangle: // to keep simple, we'll use x coord only, so it ends up as: // y2 = y1 + (x2-x1) Position[1][1] = position[0][1] + (Position[1][0] - Position[0][0]) // calc radius private rad = (Position[1][0] - Position[0][0]) / 2 rad[0][1] = rad[0][0] // must set y coord too // calc center coordinate of circle private centerpos = Draw.Offset(Position[0],rad) // move tick based on radius, but only in x tick[0][0] += rad[0][0] tick[1][0] += rad[0][0] textloc[0][0] += rad[0][0] private temp // first, set our pen: Draw.SetPen(RGB(0,0,0),1,"solid") // next, draw a circle at our screen loc: Draw.FrameEllipse(DC,Position) // now ticks, every 5 degrees: for (private.x = 0, x < 360, x += 5) // rotate temp = Draw.Transform(tick,centerpos,1,x + rot) // and draw Draw.PolyLine(DC,temp) endfor
176
// and finally text, every 30 degrees for (private.x = 0, x < 360, x += 30) // rotate the text location temp = Draw.Transform(textloc,centerpos,1,x + rot) // now calc size of text rad = Draw.GetTextExtent(DC,DoubleToStr(360-x)) // and offset location to center it temp = Draw.Offset(temp,rad/-2) // finally, draw! Draw.TextOut(DC,temp,DoubleToStr(360 - x)) endfor // for kicks, draw current rot in center of circle rad = Draw.GetTextExtent(DC,DoubleToStr(rot)) temp = Draw.Offset(Centerpos,rad/-2) Draw.TextOut(DC,temp,DoubleToStr(rot)) Here is another sample to do a floating scale gauge: // vertical version // the next two lines just make the value increment 10 units each refresh global alt = 0 alt += 10 // the coords for a tick at center {x,y} private tick = {{10,0},{20,0}} // the coordinate of the center text private textloc = {{21,0}} // the number of ticks to display: private tickcount = 10 // should probably be even // tick spacing private tickspacing = 100 // scale factor from alt units to pixels: private scale = (Position[1][1] - Position[0][1]) / (tickspacing * tickcount) // top position (in pixels) private top top[0][1] = ((Position[1][1] - Position[0][1]) / 2) - \ // the middle (tickcount / 2 * tickspacing) * scale - \ // size of 5 ticks (alt % tickspacing) * scale // the partial tick top[0][0] = 0 private starttick = floor(alt / tickspacing)*tickspacing - tickcount / 2 * tickspacing // move top based on component position top = Draw.Offset(top,Position[0]) // in this case we are going to clip to the size of the component: Draw.Clip(DC,Position) private temp // first, set our pen: Draw.SetPen(RGB(0,0,0),1,"solid") // next, draw a box at our screen loc: Draw.FrameRect(DC,Position) // calc size of text. We only care about height, and only halfsize private texthalfsize = (Draw.GetTextExtent(DC,"1") / 2)[0][1] // draw center tick: temp[0][1] = Position[0][1] + (Position[1][1] - Position[0][1]) / 2 temp[1][1] = temp[0][1] temp[0][0] = Position[0][0] temp[1][0] = Position[0][0] + 10 Draw.PolyLine(DC,temp) // now ticks. Draw an extra tick to ensure we make it out of the box. // will take care of the rest for (private.x = 0, x < tickcount+1, x++) Clipping
177
temp = Draw.Transform(tick,top,1,0) Draw.PolyLine(DC,temp) top[0][1] -= texthalfsize temp = Draw.Transform(textloc,top,1,0) Draw.TextOut(DC,temp,DoubleToStr(starttick + x * tickspacing)) top[0][1] += tickspacing * scale + texthalfsize endfor
DAQFactory has four different LED components that are almost identical except for the shape of the drawn LED. With the exception of the arrow LED, which has radio buttons for selecting the direction of the arrow, the properties for these components are identical. The expression entered will be evaluated, and if the result is non-zero, the LED is drawn in the active color. Otherwise it is drawn in the inactive color. Component Variables and Functions (advanced): please see the section on Component Names for a description on how to use these. ActiveColor BackColor Bevel strExpression InactiveColor Transparent The arrow LED adds the following: Style: 0 = right, 1 = left, 2 = up, 3 = down, 4 = left/right, 5 = up/down
The progress bar is a standard windows progress bar displaying a colored bar of length determined by an expression and a range. The bar can be smooth or segmented, horizontal or vertical and you can change the bar and background color. Component Variables and Functions (advanced): please see the section on Component Names for a description on how to use these. BackColor BarColor strExpression RangeMax RangeMin Smooth Vertical
7.18.3 Gauges
7.18.3.1 Linear Gauge and Log Gauge Component
The linear and log gauge components draw a simple straight horizontal or vertical gauge. The orientation is determined by the size of the component. If the size is wider than it is tall, then the gauge is drawn horizontal, otherwise it is drawn vertical. The two components have almost identical properties except for their tick settings.
Main: Expression: The result of the expression is used to determine the position of the gauge pointer. Range: Determines the total range of the gauge. For the Log Gauge, both the min and max values must be
7 Pages and Components7.18 The Components7.18.2 Displays7.18.2.7 Canvas Component
178
Pointer: Size: The overall size of the pointer. Margin: How far the pointer is from the main gauge line. Color: The color of the pointer Style: The type of pointer displayed Orientation: Where the pointer is positioned relative to the main gauge line. Transparent: Determines if the background is drawn or not. Background Color: The color to draw the background if Transparent is not selected. Speed Key: A key that when pressed will select this component. Min/Max: Min and Max Expressions: The results of these expressions are used to determine the location of the min
and max pointers. Both are optional. The color button to the right of these edit boxes determine the color of the particular pointers.
Size: The overall size of the min/max pointers Margin: How far the min/max pointers are from the main gauge line. Ticks: Label: Show: Determines if the gauge labels are drawn. Only available on the linear gauge. Precision: The number of digits after the decimal place displayed. Margin: How far the labels are drawn from the main gauge line. Color: The color of the text labels. Style: Determines if the labels are drawn with scientific notation or regular notation. Only available on the log
gauge.
Major: Show: Determines if the major ticks are drawn. Only available on the linear gauge. Length: The length, in pixels, of the major ticks. Color: The color of the major ticks. Minor:
179
Show: Determines if the minor ticks are drawn. Only available on the linear gauge. Count: The number of minor ticks per major tick. Length: The length, in pixels, of the minor ticks. Color: The color of the minor ticks. Alignment: How the minor ticks are drawn relative to the main gauge line. Sections:
The sections determine the background shading of the gauge. Specifying a count of 0 displays no gauge shading. Any other count, and the gauge is shaded depending on the range, as determined by the End parameters. Component Variables and Functions (advanced): please see the section on Component Names for a description on how to use these. BackColor strExpression LabelColor LabelMargin LabelPrecision MajorTickColor MajorTickLength strMax: the expression for the max indicator MaxColor strMin: the expression for the min indicator MinColor MinorAlignment: 0 = inside, 1 = center, 2 = outside MinorTickColor MinorTickLength MMMargin: the margin for the max/min indicators MMSize: the size of the max/min indicators Orientation: 0 = top/left, 1 = bottom/right PointerColor PointerMargin PointerSize PointerType: 0 = arrow/line, 1 = arrow, 2 = line, 3 = triangle RangeMax RangeMin SectionColor1 - SectionColor5 SectionCount SectionEnd1 - SectionEnd4 TickMargin Transparent The following are only available in the linear gauge: ShowLabels ShowMajor ShowMinor The following are only available in the log gauge: LabelStyle: 0 = decimal, 1 = scientific
These two components create a circular gauge with an arrow that rotates depending on the result of an expression. They both have almost identical properties except for the tick settings.
Main Page:
7 Pages and Components7.18 The Components7.18.3 Gauges7.18.3.1 Linear Gauge and Log Gauge Component
180
Expression: The result of the entered expression is used to determine the position of the main pointer. Range: These two numbers determine the total range of the gauge. Note, for the log version, both the range min
and max must be above 0.
Pointer Size: A number that determines the overall size of the main pointer. The actual affect depends on the
pointer style.
Pointer Margin: The number of pixels between the end of the pointer and the gauge ticks. Pointer Color: The color of the main pointer, not including the hub. Pointer style: Select on of four different types of pointers. Transparent: If checked, then no background is drawn. Background color: This only applies if transparent is not checked. Speed Key: If a character is provided here, pressing that key while viewing the page this component is on will
select the component.
Arc Page: Arc: Range Degrees: Determines the total arc length in degrees. 360 would be a complete circle. Start Degrees: Determines the location of the lowest range in degrees. 0 degrees is directly to the right, 90
degrees is straight up.
Show Inner / Outer Arc: Determines if the line of the arc is displayed. Hub: Show?: Determines if the hub is drawn. Size: Determines the size of the hub in pixels. Color: Determines the color of the hub. Min/Max Pointers: Max/Min: These expressions determine the position of the max or min pointer. The color box to the right of
these boxes determines the color of the pointer.
Size: The size of the max/min pointers. Margin: The number of pixels between the end of the max/min pointers and the inner arc. Style: Select from one of four pointer styles. Ticks: Margin: This determines the total margin for all pointers. The maximum of the this parameter and the individual
pointer margins is used.
181
Label: Show: Available only in the regular gauge. Precision: The number of decimal places to display Margin: The number of pixels from the outside arc to the labels Color: The color of the tick labels. Style: determines whether values are displayed in scientific notation or regular notation. Only available in the log
gauge.
Major: Show: Available only in the regular gauge. Length: The size of the major ticks in pixels. Color: The color of the major ticks. Minor: Show: Available only in the regular gauge. Count: The number of minor ticks per major tick. Has no useful effect in log gauge. Length: The size of the minor ticks in pixels. Color: The color of the minor ticks. Alignment: Determines where the minor ticks are plotted relative to the inner and outer arc. Sections:
The sections determine the background shading of the arc. Specifying a count of 0 displays no arc shading. Any other count, and the arc is shaded depending on the range, as determined by the end parameters. Component Variables and Functions (advanced): please see the section on Component Names for a description on how to use these. BackColor strExpression HubColor HubSize LabelColor LabelMargin LabelPrecision MajorTickColor MajorTickLength strMax: the expression for the max indicator MaxColor strMin: the expression for the min indicator MinColor MinorAlignment: 0 = inside, 1 = center, 2 = outside MinorTickColor MinorTickLength MMMargin: the margin for the max/min indicators
7 Pages and Components7.18 The Components7.18.3 Gauges7.18.3.2 Angular Gauge and Angular Log Gauge Component
182
MMSize: the size of the max/min indicators MMType: the type of max/min pointer: 0 = arrow/line, 1 = arrow, 2 = line, 3 = triangle PointerColor PointerMargin PointerSize PointerType: 0 = arrow/line, 1 = arrow, 2 = line, 3 = triangle RangeDegrees RangeMax RangeMin SectionColor1 - SectionColor5 SectionCount SectionEnd1 - SectionEnd4 ShowHub ShowInnerArc ShowOuterArc StartDegrees TickMargin Transparent The following are only available in the linear gauge: ShowLabels ShowMajor ShowMinor The following are only available in the log gauge: LabelStyle: 0 = decimal, 1 = scientific
The LED Bar Gauge Component draws a gauge comprising of multiple LED segments similar to those used on some audio mixers.
Main: Expression: The result of the expression is used to determine the number of LED segments that will be
illuminated.
Range: The total range of values displayed by the LED segments. Show Off Segments: Determines if segments that are not illuminated will be displayed. Size: The size of the segments along the gauge axis in pixels. Spacing: The spacing between individual segments in pixels. Margin: The spacing between the segments and the outside of the component in pixels. Direction: Determines the direction of increasing values. Style: The style of the segments. Transparent: If checked, then the background is not drawn. Background Color: If transparent is not checked, this determines the color of the background. Speed Key: A key, when pressed, will select this component. Sections: The sections determine the colors of the segments. The count must be between 1 and 3.
Component Variables and Functions (advanced): please see the section on Component Names for a description on how to use these.
183
BackColor DisplayOffSegs strExpression Margin Orientation: up = 0, down = 1, right = 2, left = 3 RangeMax RangeMin SectionColor1 - SectionColor3 SectionCount SectionEnd1, SectionEnd2 Size Spacing Style: 0 = rectangle, 1 = circle, 2 = triangle Transparent
7.18.4 Compasses
7.18.4.1 Compass Component
Expression: The result of the expression determines the bearing displayed. Pointer: Size: The overall size of the bearing pointer. Margin: The distance from the main hub to the pointer in pixels. Color: The color of the pointer. Style: The type of pointer displayed. Ticks: Margin: The distance from the main hub to the ticks in pixels. Length: The overall length of the ticks in pixels Color: The color of the ticks. Width: The width of the ticks in pixels. Direction Display: Show: Determines if the textual display of the bearing is displayed in the center of the hub. Precision: The number of digits after the decimal point displayed. Color: The color of the textual bearing display. Labels: Inner Margin: Determines the distance from the main hub to the bearing labels in pixels. Outer Margin: Determines the distance from the outside of the compass to the labels in pixels
7 Pages and Components7.18 The Components7.18.3 Gauges7.18.3.3 LED Bar Gauge Component
184
Color: The color of the labels. Transparent: If checked, then no background is drawn. Background Color: If transparent is not checked, this determines the color of the background. Scale Background: Determines the background color behind the ticks, labels, and pointer. Speed Key: A key that when pressed selects this component.
Component Variables and Functions (advanced): please see the section on Component Names for a description on how to use these. BackColor DirectionColor DirectionPrecision strExpression LabelColor LabelInnerMargin LabelOuterMargin PointerColor PointerMargin PointerSize PointerType: 0 = triangle, 1 = circle, 2 = line ScaleBkColor ShowDirection TickColor TickLength TickMargin TickWidth Transparent
Displays a compass that can display three different headings. The first is displayed as a textual label in the center, the second is displayed by moving a pointer on top of a scale, and the third rotates the scale under a fixed pointer.
Center Display: Expression: The result of the expression is displayed in textual form in the center of the component in the color
determined by the color button to the right of the edit box.
Precision: Determines the number of digits displayed after the decimal point. Height/Width: Determines the size background box behind the textual display. The units are in characters. Background color: Determines the color of the background box displayed behind the textual display in the
center of the component.
Pointer 1: Expression: The result of the expression determines the position of pointer 1. Pointer 1 is the fixed line pointer
at the top of the control. The result is displayed by rotating the scale so the proper value is displayed behind the pointer. The color of the pointer is determined by the color button to the right of the edit box.
185
Expression: The result of the expression determines the position of pointer 2. Pointer 2 is the rotating triangular
pointer. The position is determined after the scale is rotated for Pointer 1.
Height/Width: Determines the size of the triangular pointer. Units are in characters. Scale: Margin: The distance from the outside of the bezel to the scale labels in characters. Background / Font Color: Determines the colors used to draw the scale. Labels: Determine the labels displayed above and below the textual display and their colors. Border Style: The type of border displayed when drawing the background. Only used when transparent is not
selected.
Transparent: Determines if a square background is drawn under the component. Background Color: Determines the color of the background if transparent is not selected. Inner Color: The background color drawn inside of the scale circle. Speed Key: A key, if pressed, which will select the current component.
Component Variables and Functions (advanced): please see the section on Component Names for a description on how to use these. BackColor strBottomLabel BottomLabelColor BorderType: 0 = none, 1 = raised, 2 = lowered DisplayBkColor DisplayColor strDisplayExpression DisplayHeight DisplayPrecision DisplayWidth InnerColor Pointer1Color strPointer1Expression Pointer1Width strPointer2Expression Pointer2Height Pointer2Width ScaleBkColor ScaleFontColor ScaleMargin strTopLabel TopLabelColor Transparent
7.18.5 Percent
7.18.5.1 Percent Bar and Pie Chart Component
These two components display a shaded bar or pie chart based on multiple values. Both have similar properties with a few exceptions that adjust how the components are drawn.
Items: This table determines the different items that will be used to fill the bar or pie. You can add as many
items as you need with the "Add" button, or remove items with the "Delete" button. Each row has the same three
186
properties: Expression: The result of the expression is used to determine the value used in the bar or pie. The percentage displayed is this value divided by the sum of the values for all items. Text: The text to be displayed in the legend. Color: The color used to shade the percentage used by the item.
Title: A title label displayed at the bottom of the component. Title Margin: The distance from the bottom of the component to the title in pixels. Outer Margin: The distance from the sides of the component to the bar or pie and legend in pixels. Bar Width: The width of the bar in a percent bar component in pixels. Start Degrees: The direction, with 0 being to the right, and 90 being up, where the first item will start to be
drawn. Items are drawn in counter-clockwise order.
Legend: Margin: The distance between the legend and the bar or pie in pixels. Show Percent: If checked, the actual percentage of each item is displayed next to its legend. Show Value: If checked, the actual value determined by each item's expression is displayed next to its legend. Precision: Both the Percent and Value have a Precision parameter that determines the number of digits displayed
after the decimal.
Transparent: If checked, then the background is not drawn. Background Color: If transparent is not checked, this determines the color the background is drawn in. Speed Key: A key, that when pressed, will select the current component.
Component Variables and Functions (advanced): please see the section on Component Names for a description on how to use these. AddSection(expression, [color], [label]): adds another section to the display. Only the expression parameter is required. Typically you will call ClearSections() first then call AddSection() multiple times to create a new display. BackColor strCaption ClearSections(): clears all the values from the display LegendMargin OuterMargin PercentPrecision ShowPercent ShowValue TitleMargin Transparent ValuePrecision The percent bar component adds: BarWidth The pie chart component adds: StartDegrees
187
7.18.6 Graphs
7.18.6.1 2D Graph Component
This component displays a two dimensional graph. This can be either a Y vs. Time trend graph, or an X/Y graph. There are many options available and so the graph component is discussed in its own chapter.
The 3D graph component is for displaying 3D data. 3D data is an array with rows and cols, or cols and depth. A channel with history only has 2 dimension, rows and value. A spectrum channel with history is 3D, where the rows are the historic values, and cols are a particular spectrum. An image channel with history is 4D, where each row corresponds to a single image with cols and depth. It is these last two types of data which can be displayed with this component. This display is 3 dimensional view, either as a contour or as a waterfall type graph.
Main: Graph Style: one of three styles, 3D Surface, 3D Bar, and Scatter/Waterfall. Within each style there are several
plotting method choices. Do not use the 3D bar type with large amounts of data as it takes much longer to plot then the other types.
Plotting Method: determines how to plot the selected style. The options vary depending on the style.
Experiment with the different methods and styles to see how the 3D graph might be able to plot your data.
Expression: the result of the expression is used to determine what is drawn. The result should be three
dimensional, i.e. it will have rows and cols, or cols and depth.
Scale From / To: Determines the Y (vertical) axis scaling. This is an expression. Viewing Height: the height above the XZ plane in degrees to view the graph. Valid values are 0 to 45. Rotation: the rotation around the y axis to view the graph. Valid values are 0 to 359. XZ axis scaling: the x and z axis values are normally just the point number in the given dimension (i.e. rows,
cols or depth). If you prefer to scale either axis, provide an expression the results in an array of values with the appropriate number of points. You can then scale within those units using the Scale From and Scale To parameters.
Details: Y Color Shading: The color table determines the color of each pixel. The threshold parameter determines the
upper level at which a given color is used. This only works with certain Graph Styles and Plotting Methods.
Shade between colors: If checked, the color of each pixel will be a cross between the two neighboring colors
in the color table. Otherwise, the color is simply the color with the smallest threshold above the actual data point value.
Show Contour?: If checked, a flat contour graph is displayed. There are four options which determine how and
where the contour is plotted.
Add skirts: If checked, skirts are added. Skirts are solid areas extending from the contour down to the XZ axis
plane.
188
The image component is for displaying 3D data. 3D data is an array with rows and cols, or cols and depth. A channel with history only has 2 dimension, rows and value. A spectrum channel with history is 3D, where the rows are the historic values, and cols are a particular spectrum. An image channel with history is 4D, where each row corresponds to a single image with cols and depth. It is these last two types of data which can be displayed with this component. This display is an Indian blanket or contour type where each value is represented by a pixel or block of pixels of a particular color.
Expression: the result of the expression is used to determine what is drawn. The result should be three
dimensional, i.e. it will have rows and cols, or cols and depth.
Colors: If Data that is RGB is not checked, the color table determines the color of each pixel. The threshold
parameter determines the upper level at which a given color is used.
Shade between colors: If checked, the color of each pixel will be a cross between the two neighboring colors
in the color table. Otherwise, the color is simply the color with the smallest threshold above the actual data point value.
Data is RGB: If checked then the color table is not used and the actual data point is assumed to be an RGB color
value.
Data is B & W (32 bit packed): If checked then the data is assumed to be 1 bit color (black and white)
packed into 32 bit numbers. Each value in the array therefore represents 32 pixels in the X direction. The colors of the 0's and 1's are determined by the first two colors in the color table.
X / Y Scaling: The result of these expressions determines the number of pixels used to draw each data point in
the X and Y directions. Use this to zoom in on the image.
X / Y Offset: Data is drawn from the top left corner, where the first row, col or depth is the top left. The offset
makes the top left corner a different location in the data.
Speed Key: A key, when pressed, that will select the current component.
Component Variables and Functions (advanced): please see the section on Component Names for a description on how to use these. BW strExpression RGBColor Shaded strXOffset strXScale strYOffset strYScale
Displays a multiple bar graph similar to a stereo equalizer with peak values. Although the scaling is quantitative, there are no ticks or labels on this component. If the peak markers are displayed, clicking on the component will reset them.
Mode: The component can take data in one of two methods: Array: The array expression is evaluated and each array element of the result is displayed as a separate bar. The
total number of bars displayed is determined by the size of the resultant array.
Individual Expressions: A separate expression, which should evaluate to a scalar value, is used to
determine the height of each bar. The total number of bars is determined by the Bar Count parameter, and the expressions are entered into the table.
189
Spacing: The distance between consecutive bars in pixels. Color: The color of the bars. Range: The range of valid values for the bars. Show Peaks: If checked, then a horizontal line is displayed with the peak value of each bar. Color: The color of the peak lines if drawn. Transparent: If checked then only the bars and peak lines are drawn. Background color: The color of the background displayed behind the bars if Transparent is not checked. Speed Key: A key that when pressed will select the component.
Component Variables and Functions (advanced): please see the section on Component Names for a description on how to use these. BackColor BarColor Max Min PeakColor ShowPeak Transparent
7.18.7 Buttons_&_Switches
7.18.7.1 Button Component
Displays a standard windows button. Many different actions can be assigned when the user clicks the button. These are the same actions available on many other components.
Text: The caption that is displayed on the button. Text Color: The color of the caption displayed on the button. Background Color: The color of the button. Font / Font Size: The font information used to draw the caption. Speed Key: A key that when pressed will select this component.
Component Variables and Functions (advanced): please see the section on Component Names for a description on how to use these. BackColor strCaption strFontName FontSize ForeColor
The check box is another standard windows control for selecting a Boolean value. Caption: The text displayed to the right of the box. Set Channel: The channel or variable that will be set with either a 1 or 0 depending on the state of the check box. This also determines whether the check is displayed in the box.
190
Text Color, Font, and font size: Determines the attributes of the caption. The check box size is determined by the caption font size as well. Speed Key: A key that will select this component. You can also set the component up to display an array of check boxes. The array can have multiple columns and rows. The Set Channel is set to an array result corresponding to each check box. So if you have an array size of 3 by 2, you would get an array with 3 columns and 2 rows in your set channel. Array? Check this to enable array mode. When in array mode, the caption is not displayed. Array Size: Specifies the number of columns and rows. Array Margin: Specifies the number of pixels to put between each column or row. The size of each individual check box is determined by the size of the component itself and the array size and margins. Component Variables and Functions (advanced): please see the section on Component Names for a description on how to use these. BackColor strCaption strFontName FontSize ForeColor strSetChannel
This control displays a standard windows spin button. A spin button is actually two buttons that change a particular channel or variable by a particular interval up or down when clicked. Action Channel: The output channel or variable that is changed when the component is clicked. Interval: The amount the channel or variable is changed when the up or right button is clicked. The negative of this value is used when the down or left button is clicked. Vertical: If checked then the spin button is displayed as up and down buttons, otherwise it is displayed as left and right buttons. Arrow Color: The color of the triangular arrows drawn in each button. Button Color: The background color of each button. Speed Key: A key that will select this component. Component Variables and Functions (advanced): please see the section on Component Names for a description on how to use these. BackColor strCaption strFontName FontSize ForeColor Interval strSetChannel Vertical
Displays a paddle type lever switch that can control an output channel or variable. Set Channel: The output channel or variable that determines the position of the switch and that will be toggled between 0 and 1 when the switch is clicked. Enabled: If not checked, then the component will not respond to a mouse click.
191
Transparent: If checked, then the background is not drawn. Background: Determines the color the background is drawn in if Transparent is not checked. Speed Key: A key that will select this component. Component Variables and Functions (advanced): please see the section on Component Names for a description on how to use these. BackColor Enabled strSetChannel Transparent
Displays a rocker type switch that can control an output channel or variable. Set Channel: The output channel or variable that determines the position of the switch and that will be toggled between 0 and 1 when the switch is clicked. Enabled: If not checked, then the component will not respond to a mouse click. Transparent: If checked, then the background is not drawn. The background is a thin area around the actual switch. LED Color: Determines the color of the LED displayed on the switch. The color selected is the color when the switch is active. The off color is automatically determined from the on color. Speed Key: A key that will select this component. Component Variables and Functions (advanced): please see the section on Component Names for a description on how to use these. BackColor Enabled LEDColor strSetChannel Transparent
Displays a slider type toggle switch that will set an output channel or variable to 1 or 0. Set Channel: The output channel or variable that determines the position of the switch and that will be changed when the switch is clicked. Enabled: If unchecked, then the component will not respond to mouse clicks. Orientation: Determines the direction the switch is drawn. Height: Determines the height, in pixels, of the sliding part of the switch. Transparent: If unchecked, then the background of the switch is drawn in grey. Speed Key: A key that will select the current component. Component Variables and Functions (advanced): please see the section on Component Names for a description on how to use these. BackColor Enabled Horizontal strSetChannel SwitchHeight Transparent
192
Displays a standard valve symbol in a color determined by a channel or variable. Clicking on the component will toggle the channel or variable between 0 and 1. Set Channel: The variable or channel that determines the color of the valve and will be changed when the component is clicked. Enabled: If unchecked, then the component will not respond to mouse clicks. Orientation: Determines whether the valve is drawn horizontally or vertically. Open/Close Color: Determines the color of the valve when it is in the Open (1) or closed (0) state. The state is determined by the Set Channel. Change Body Color: If checked then the entire valve color is set to the Open or Closed color. Otherwise, only the valve top is changed and the rest of the valve is drawn in grey. Transparent: Determines if the background is drawn behind the valve. Background: Determines the color of the background if Transparent is not checked. Speed Key: A key that will select this component. Component Variables and Functions (advanced): please see the section on Component Names for a description on how to use these. BackColor ChangeBodyColor CloseColor Enabled Horizontal OpenColor strSetChannel Transparent
Displays a two directional switch that changes an output channel or variable by a specified interval up or down.
Set Channel: The channel or variable to change with every click. If the channel has not been initialized before
clicking, it is assumed to have a 0 value.
Interval: The amount to change the set channel by with each click. Specifying a negative number causes the
component to operate in reverse: a click on the upper part of the switch decrements the channel or variable.
Repeat Delay: The switch can be held for rapid adjustment. The repeat delay is the number of milliseconds
after the switch is first pressed and not released before the rapid adjustment begins. This works just like holding down a key on the computer.
Repeat Rate: Once the rapid adjustment begins, the output channel will be changed by the interval once every
repeat rate (in milliseconds) until the switch is released by releasing the mouse button.
Enabled: If checked, then the switch is active, otherwise the switch will not respond to mouse clicks. Transparent: If checked then the background is not drawn. The background is a small border area around the
switch.
Background color: If transparent is not checked, this determines the color of the background. Speed Key: A key that selects the current component.
Component Variables and Functions (advanced): please see the section on Component Names for a
193
description on how to use these. BackColor Enabled Interval RepeatDelay RepeatRate strSetChannel Transparent
Displays a four directional switch that changes two output channels or variables by a specified interval up or down. This works just like the 3 way rocker, but in two dimensions. Set Channel X/Y: The channel or variable to change with every click. If the channel has not been initialized before clicking, it is assumed to have a 0 value. The X version is set by the left and right arrows, while the Y version is set by the up and down arrows. Interval X/Y: The amount to change the set channel by with each click. Specifying a negative number causes the component to operate in reverse: a click on the upper part of the switch decrements the channel or variable. Repeat Delay: The switch can be held for rapid adjustment. The repeat delay is the number of milliseconds after the switch is first pressed and not released before the rapid adjustment begins. This works just like holding down a key on the computer. Repeat Rate: Once the rapid adjustment begins, the output channel will be changed by the interval once every repeat rate (in milliseconds) until the switch is released by releasing the mouse button. Enabled: If checked, then the switch is active, otherwise the switch will not respond to mouse clicks. Transparent: If checked then the background is not drawn. The background is a small border area around the switch. Background color: If transparent is not checked, this determines the color of the background. Speed Key: A key when pressed that selects the current component. Component Variables and Functions (advanced): please see the section on Component Names for a description on how to use these. BackColor Enabled IntervalX IntervalY RepeatDelay RepeatRate strSetChannelX strSetChannelY Transparent
7.18.8 Edit_Controls
7.18.8.1 Edit Box, Password Edit, and Multiline Edit Box Component
These three components display a standard edit box which is an area on the screen where a user can enter in data. The normal edit box and password edit box allows only one line of text but has the option to submit changes when the Enter key is pressed. The only difference between these two components is that the password edit displays *'s in place of the characters typed. The multiline edit box allows multiple lines of data, but moves to the next line when the Enter key is pressed rather than submitting the changes. All three have pretty much the same properties: Caption: An optional caption displayed to the left of the box. Set Channel: An output channel or variable that will be set to the contents of the edit box. Unlike most other components, this component will not display the current contents of the channel or variable, but instead displays the 7 Pages and Components7.18 The Components7.18.7 Buttons_&_Switches7.18.7.8 Three Way Rocker Component
194
user entry. If the output channel or variable is a numeric data type the entry will be converted to a number before setting the channel or variable. Submit only if changed: if selected then the set channel will only be set to the entered value if that value is different than the current contents of the set channel. Set on Exit: If checked then the set channel is set to the contents when the user clicks outside the edit box. This is only available in the normal edit box and password edit component. Set on Exit: If checked then the set channel is set to the contents when the user clicks outside the edit box. This is only available in the multiline edit box component. Set on Set Button press: If checked, a button is displayed to the right of the box. When this button is clicked, the set channel is set to the contents of the box. Set button caption: The caption for the set button. Set on Submit button press: If checked, the set channel is set to the contents of the box when another component on the page has a submit action and that component is clicked. Read-only when: if the expression entered here evaluates to a non-zero value, then the edit box becomes readonly. If this is left empty, then the box is never read-only. Color Expression: An expression that is used to determine the color of the control. Used in conjunction with the Active Color and Inactive Color pages. Units: An optional text that displays to the right of the box. Font/Font Size: Sets the font and font size for all the text in the component. Speed Key: A key that selects this component. Active/Inactive color: These two pages determine the colors for the control. If left blank, the control always draws in black on white. The active color tables are used when the control is editable. The inactive tables are used when the control is read-only, as determined by the "Read-only when" expression. The tables and coloring works just like the common color tables. Component Variables and Functions (advanced): please see the section on Component Names for a description on how to use these. BackColor: this will reset the table of colors to a single background color. strBlink strCaption strColorExpression strContents: sets the contents displayed in the edit box. Setting this will overwrite anything the user has entered into the edit box. DoOnCR DoOnSet DoOnSubmit strFontName ForeColor: this will reset the table of colors to a single foreground color. InvalidBackColor: this will reset the table of colors to a single invalid background color. InvalidForeColor: this will reset the table of colors to a single invalid foreground color. OnlyIfChanged ReadOnly strSetButtonCaption strSetChannel strUnits strVisible strXSize XSizeMax XSizeMin
195
This control displays a standard windows date/time control. This control allows the selection of date, time or both with a drop down month calendar. Caption: Optional text that will be displayed to the left of the date. Set Channel: The output channel or variable that will be set with the date / time. The date and time is formatted using the standard DAQFactory seconds since 1970 format. Set on Set Button Press: If checked, the Set Channel is set to date/time selected when the button displayed to the right of the date/time is clicked. Set button caption: The caption for the Set button displayed when Set on Set Button press is selected. Set on Submit button press: If checked, the Set Channel is set to the date/time selected when another component on the page has a Submit action and that component is clicked. Display Date / Time: You can optionally display either the date or time or both. Date/Time ratio: if you are displaying both date and time, this is the ratio of the size of the date part of the control to the size of the time part. Font / Font Size: sets the font and font size for all the text used by this component. Speed Key: A key that will select this component. Date/Time Format: this determines how the date is displayed. Since this is a Windows control it uses a code determined by Windows: "d" The one- or two-digit day. "dd" The two-digit day. Single-digit day values are preceded by a zero. "ddd" The three-character weekday abbreviation. "dddd" The full weekday name.
"h" The one- or two-digit hour in 12-hour format. "hh" The two-digit hour in 12-hour format. Single-digit values are preceded by a zero. "H" The one- or two-digit hour in 24-hour format. "HH" The two-digit hour in 24-hour format. Single-digit values are preceded by a zero.
"m" The one- or two-digit minute. "mm" The two-digit minute. Single-digit values are preceded by a zero. "M" The one- or two-digit month number. "MM" The two-digit month number. Single-digit values are preceded by a zero. "MMM" The three-character month abbreviation. "MMMM" The full month name.
7 Pages and Components7.18 The Components7.18.8 Edit_Controls7.18.8.2 Date & Time Edit Component
196
"y" The one-digit year (that is, 1996 would be displayed as "6"). "yy" The last two digits of the year (that is, 1996 would be displayed as "96"). "yyy" The full year (that is, 1996 would be displayed as "1996"). The quotes are not entered. If you want non-date or time characters (other than space), enclose them in quotes. Example: dddd MMMM d',' yyyy displays Tuesday January 20, 2004 Component Variables and Functions (advanced): please see the section on Component Names for a description on how to use these. strBlink strDateFormat DisplayDate DisplayTime DoOnSet DoOnSubmit Ratio strSetButtonCaption strSetChannel strTimeFormat strVisible strXSize XSizeMax XSizeMin
7.18.9 Selection
7.18.9.1 Combo Box and Radio Buttons Components
Both of these controls allow the user to select from a list of options. The difference is how they are presented. The ComboBox is a standard Windows control that displays the selection with a down arrow next to it. If the user clicks the down arrow, a box appears with the possible selections. The radio buttons displays a radio button with prompt for each option, with the selection having a filled in button. Set Channel: The channel or variable that will be set to the selected value. Buttons: This table holds the available options. Use the Add button to add new options, or the Delete button to remove old ones. It has three columns: Prompt: This is how the option will display on the screen. This is what the user sees. Value: This is what the Set Channel gets set to when the user selects this option. Order: This determines the order that the options get listed. It is alphabetical by this column. Speed Key: A key that will select this component. The radio buttons component adds the following properties: Text color, Font and Font Size: These determine the font information used to draw all the text for the buttons. Note: If you can't get your combo box to open, it is usually because you have made the component too short. The
197
size of the combo box component determines the open size of the combo box, not the closed size. If you make the component the same size as the closed box, or only slightly taller, then the box won't be able to open. Component Variables and Functions (advanced): please see the section on Component Names for a description on how to use these. Both Components: AddChoice(option, value): adds a new choice to the component. Both parameters are required. Option is a string that is displayed to the user. Value is what the SetChannel is set to if the user selects the option. ClearChoices(): removes all the choices from the component strSetChannel Combo Box only: strContents Radio Component only: BackColor strCaption strFontName FontSize ForeColor
This is an advanced component and only usable with scripting. Because of this, you must name the component. The component name can be assigned using the normal method or through the properties window for the component. The properties window also allows you to enter an event sequence that is executed, just like the Quick Sequence action on other components, when the user double clicks on a tree item. The event provides two private variables, Private.strItemText which is the actual text that was clicked on, and Private.ItemData which is a numeric value that you assigned to each item. But of course you first must fill the tree list. This can only be done with scripting with the following five functions:
InsertItem(Text, Parent, Insert After, Data): Inserts a new item with the given text into the tree.
Returns a handle to the item which can be used for subsequent commands. Parent is the parent item or 0 for the root. Insert after is the item to insert this item after or 0 for the last item. Data is a user definable value that is returned to you in the double click event.
DeleteItem(Item): Deletes the given tree item. Item is the handle of the desired item returned when you did
InsertItem.
Expand(Item): Expands the given item. This is the same as the user clicking on the + to the left of the item.
Has no effect if the item does not have any children.
EnsureVisible(Item): Scrolls the item list so that the given item is visible. DeleteAllItems(): Clears the tree list.
7.18.10 Sliders_&_Knobs
7.18.10.1 Knob Component
Main: Set Channel: The specified channel or variable will be set to the value corresponding to the position of the
knob.
7 Pages and Components7.18 The Components7.18.9 Selection7.18.9.1 Combo Box and Radio Buttons Components
198
Update Rate: The maximum rate the Set Channel will be set by the knob. By default this is 0, which means as
fast as the knob is moved. With serial and other slow devices, this can often be too fast and can bog down the system. To avoid this, you can control the maximum update rate of the channel. Note that when the knob is released the Set Channel is set to the knob's final value.
Start Degrees: The position in a circle of the minimum point on the knob. 0 is to the right, 90 is up. Arc Length: The number of degrees the knob can turn. Positive values are clockwise, negative are counter
clockwise. You can make multiturn knobs by specify a multiple of 360, for example 720 for a 2-turn knob. You will probably want to turn off automatic labels however with multiturn knobs. For a jog wheel / knob, see below.
Jog Wheel: if checked then the knob will act like a jog wheel. A jog wheel is a knob with no limits. The range
max determines the number of units to increase or decrease with each revolution. The range min is not used. Neither is start degrees, arc length, or labels. You can then select clockwise or counter clockwise rotation for positive values.
Update Interval: Knobs and sliders will update the output very rapidly as the knob is turned. For slower
devices, especially serial and Ethernet based devices, this can cause problems and bog down the communications. To prevent this, you can set the update interval to a non-zero value and this will specify the maximum interval the output will be updated.
Knob Style: Determines how the knob is drawn. Position Display: Show?: If checked, the actual position of the knob is displayed in textual form in the center of the knob. Precision: The number of digits to the right of the decimal for the position display. Units: If entered, this will be displayed to the right of the position display. Indicator: Size: The overall size of the indicator. Margin: The distance from the outside of the knob to the indicator in pixels. Color: The color of the indicator bar / spot. Indicator style: Determines the type of bar displayed. Transparent: If checked, the background is not drawn. Background: If Transparent is not checked, the color of the background. Speed Key: A key that when pressed selects this component. Ticks: Margin: The distance between the ticks and the outside of the knob. Ticks Label: Show: If checked, labels are drawn next to the major ticks. Precision: The number of digits displayed after the decimal.
199
Margin: The distance between the ticks and the labels in pixels. Color: The color of the labels. Major Ticks: Show: If checked, major ticks are drawn. Count: The number of major ticks to display over the entire range. Length: The size of the tick marks in pixels. Color: The color of the tick marks. Minor Ticks: Show: If checked, minor ticks are drawn. Count: The number of minor ticks per major ticks to display. Length: The size of the tick marks in pixels. Color: The color of the tick marks. Alignment: The position of the minor ticks relative to the major ticks.
Component Variables and Functions (advanced): please see the section on Component Names for a description on how to use these. BackColor IndicatorColor IndicatorMargin IndicatorSize IndicatorStyle: 0 = lowered dot, 1 = raised dot, 2 = dot, 3 = line center, 4 = line, 5 = triangle KnobStyle: 0 = raised edge, 1 = raised, 2 = sunken, 3 = sunken edge MajorTickColor MajorTickCount MajorTickLength ArcLength MinorTickAlign: 0 = inside, 1 = center, 2 = outside MinorTickColor MinorTickCount MinorTickLength PositionPrecision strPositionUnits RangeMax RangeMin strSetChannel ShowMajorTicks ShowMinorTicks ShowPosition ShowTickLabels StartDegrees TickLabelColor TickLabelMargin TickLabelPrecision TicksMargin Transparent UpdateRate
200
Main: Set Channel: The specified channel or variable will be set to the value corresponding to the position of the
slider.
Range: The total range of the slider. Update Interval: The maximum rate the Set Channel will be set by the slider. By default this is 0, which
means as fast as the slider is moved. With serial and other slow devices, this can often be too fast and can bog down the system. To avoid this, you can control the minimum update interval of the channel. Note that when the slider is released the Set Channel is set to the slider's final value.
Track Style: Determines the type of track the slider slides on. Track Color: The color of the track. Ends Margin: The distance from the track to the edge of the component. Reverse Scale: If checked, the scale will go in the opposite direction. Orientation: Determines whether the track runs horizontally or vertically Indicator: Height / Width: The size of the indicator bar in pixels. Color: The color of the indicator bar. Bar style: Determines the type of bar displayed. Transparent: If checked, the background is not drawn. Background: If Transparent is not checked, the color of the background. Speed Key: A key that when pressed selects this component. Ticks: Margin: The distance between the ticks and the slider track. Tick orientation: Determines the position of the ticks relative to the slider track. Ticks Label: Show: If checked, labels are drawn next to the major ticks. Precision: The number of digits displayed after the decimal. Margin: The distance between the ticks and the labels in pixels. Color: The color of the labels.
201
Major Ticks: Show: If checked, major ticks are drawn. Count: The number of major ticks to display over the entire range. Length: The size of the tick marks in pixels. Color: The color of the tick marks. Minor Ticks: Show: If checked, minor ticks are drawn. Count: The number of minor ticks per major ticks to display. Length: The size of the tick marks in pixels. Color: The color of the tick marks. Alignment: The position of the minor ticks relative to the major ticks.
Component Variables and Functions (advanced): please see the section on Component Names for a description on how to use these. BackColor EndsMargin Horizontal IndicatorColor MajorTickColor MajorTickCount MajorTickLength MaxDegrees MinorTickAlign: 0 = inside, 1 = center, 2 = outside MinorTickColor MinorTickCount MinorTickLength PointerMargin PointerSize PointerStyle: 0 = LED, 1 = Arrow, 2 = Bar, 3 = Bar/Line, 4 = Colored Bar PositionPrecision PositionUnits RangeMax RangeMin ReverseScale strSetChannel ShowMajorTicks ShowMinorTicks ShowPosition ShowTickLabels StartDegrees TickLabelColor TickLabelMargin TickLabelPrecision TickOrientation: 0 = bottom/right, 1 = top/left TicksMargin TrackStyle: 0 = box, 1 = line, 2 = bevel lowered, 3 = bevel raised TrackColor Transparent
202
Action Channel: The channel or variable that will be set to the position of the scroll bar. Range: The values for the extreme ends of the scroll bar. Step Size: The amount the position is adjusted when the user clicks on the arrows at the ends of the scroll bar. Vertical: If checked, the scroll bar is displayed vertically. Arrow Color: The color of the arrows at the ends of the scroll bar track. Button Color: The background color of the arrow buttons at the ends of the scroll bar track. Track Color: The background color of the track. Tracker Color: The color of the moving box running in the track. Speed Key: A key that when pressed will select this component.
Component Variables and Functions (advanced): please see the section on Component Names for a description on how to use these. BackColor strCaption strFontName FontSize ForeColor RangeMax RangeMin strSetChannel StepSize TrackColor TrackerColor
Step 2: Under the application menu select Tools => Symbol Factory. Click on the 3-D green button (or any other
2011 AzeoTech, Inc.
203
symbol) and select Copy. Go to PAGES: right click on Page_0 and select Paste.
Step 3: Go back to the symbol factory and copy the 3-D red button. Right click on the 3-D green button and
select Properties... Main TabSelect Add and double click in the blank Symbol: window between Thres: and Rotation. This should insert the image. Double click in the Thres: window for the 3-D red button and type 1. Double click in the Thres: window for the 3-D green button and type 0. Expression: MyChannel[0] Action TabAction: Toggle Between Action Channel: MyChannel Toggle Between: 0 and 1 Click OK
Step 4: Click on the button to toggle and set their initial values. When you click on the button, they should change
symbols going between the red and green 3-D symbols.
Step 5: You can add Variable Display components and Descriptive Text components to enhance the look of you
sample.
Step 1: In the Workspace right click on Page_0 and right click on the page to the right and select Buttons &
Switches => Button.
Step 2: Select the button you just created and give it the follow properties.
Main TabText: Login Action TabAction: Quick Sequence Sequence: Copy the code below Private string strEntered = System.EntryDialog("Enter Password:") if (!IsEmpty(strEntered)) if (strEntered == "password") Page.CurrentPage = "Protected" return endif endif System.MessageBox("Invalid Password!") Click OK.
Step 3: In the Workspace click on Page_0 and right click on a blank area of the page to the right and create a
second button. Select Buttons & Switches => Button.
Step 4: Select the button you just created and give it the follow properties.
7 Pages and Components7.19 Questions, Answers and Examples7.19.1 Displaying a different symbol based on a value
204
Main TabText: Login Action TabAction: Quick Sequence Sequence: Copy the code below private string strEntered while (1) strEntered = System.EntryDialog("Enter Password:") if (IsEmpty(strEntered)) // if nothing is entered, assume Cancel was pressed return endif if (strEntered == "password") Page.CurrentPage = "Protected" return endif System.MessageBox("Invalid Password!") endwhile Click OK Note: The second button will continually prompt the user for the password until they get it right where the first button will only ask for it once.
Step 5: Go to PAGES: located in the workspace and right click on a new page and select Page Properties. Give it
the page name Protected as this is the page we want it to switch to when the password is correct.
Step 6: Click on your buttons and verify that the first button delivers a message valid or invalid. The second
button should continue to prompt the user until a valid password is entered or cancel is selected.
Step 1: In the Workspace click on Page_0 and right click anywhere on the page to the right and select Buttons &
Switches => Button.
Step 2: Select the button you just created and give it the follow properties.
Main TabText: Login Action TabAction: Quick Sequence Sequence: Copy the code below // first initialize variables: global string strUser global string strPassword strUser = "" strPassword = "" // and clear out edit boxes Component.PasswordPrompt.Contents = "" Component.UserNamePrompt.Contents = "" // then popup window: Page.Login.PopupModal() Click OK
205
This sequence clears out any previous user / password that may have been entered and then displays the Login page in a modal popup. A modal popup is one that requires the users attention until it is closed. The two lines, Component.PasswordPrompt... and Component.UserNamePrompt... both clear the contents of the edit box.
Step 3: In the Workspace right click on Page_1 and select Page Properties. Give it the page name Login. Step 4: In the page you just called "Login" right click anywhere on the page and select Edit Controls => Edit Box.
While this component is still highlighted hit Ctrl-D to Duplicate it. Select the first edit box and go to its properties. Main TabCaption: User Name Set Channel: strUser Click OK While the component is still selected, right click on it and select Component Name... Give this component the name UserNamePrompt. We have to name the component so we can access it from the sequence script we wrote above, Component.UserNamePrompt.Contents = "". Select your second edit box and go to its properties. Main TabCaption: Password Set Channel: strPassword Click OK While the component is still selected, right click on it and select Component Name... Give this component the name PasswordPrompt.
Step 5: In the same page right click in a blank area of the page and select Buttons & Switches => Button. Right
click on the button to go to its Properties. Main TabText: Login Action TabAction: Submit Click Add to add a new action: Action: Quick Sequence Sequence: Copy the code below // // // // // note that we have a submit action as the first action, then this quick sequence. This is to force the edit boxes to update before we check for proper user+password
if ((strPassword == "password") && (strUser == "user")) // if correct, close popup Page.Login.ClosePopup() // and change page: Page.CurrentPage = "Protected" return endif // incorrect, so prompt. You // could optionally close the // popup too. System.MessageBox("Unknown username / password")
7 Pages and Components7.19 Questions, Answers and Examples7.19.3 Create a popup for user name and password
206
Click OK Highlight all the components on this page by holding the Ctrl key and left clicking and drag a box around all three components. Move all of them to the top left corner of the page. When a page is displayed in a popup, the window is automatically sized to the components on the page starting from the top left corner of the screen. If we don't move our components to the top left corner, we'll have a bigger window than necessary with a lot of white space to the top and left of the components.
Step 6: Create a third page. This is the page that will be password protected. Right click on the page in the
Workspace you wish to be protected and select Page Properties. Give it the page name Protected. This is the page that the user will only be able to access by going through the login.
Step 7: Click on your buttons and verify that the proper components for user name and password are present.
Insert the proper name and password.
Step 1: Go to PAGES: in the Workspace and select a blank page to work in. Right click on the blank page and
select Buttons & Switches => Button. For this sample create 13 buttons. The quick way to do this is to hit Ctrl-D with the first component still selected to duplicate the component.
Step 2: Go to each of the buttons Properties by right clicking on the button and selecting Properties...
Main TabText: 1 Action TabAction: Quick Sequence Sequence: Component.EditBox.strContents += "1" Leave all else to defaults Click OK Repeat this step for nine other buttons. Set each button up for the appropriate number until you have a button for 09.
Step 3: Go to the properties of one of your remaining undefined buttons. We will set this button as a clearing
button. Main TabText: Clear Action TabAction: Quick Sequence Sequence: Component.EditBox.strContents = "" Leave all else to defaults
207
Click OK
Step 4: Right click on a blank area of the page and select Edit Controls => Edit Box. While your new Edit Box is
still highlighted right click on it and select Component Name... Give it the name EditBox. Next, right click on the edit box and select Properties... Set Channel: Var.strTotal Check Set on Set Button Press Set Button Caption: # Leave all else to defaults Click OK
7 Pages and Components7.19 Questions, Answers and Examples7.19.4 Create a popup numeric keypad
208
Step 7: Organize your components in the top left corner your page. The manner in how you organize them is how
they will be displayed in the pop-up window. Note your buttons can be resized by and arranged by using the Layout option in DAQFactory.
Step 8: Go to another blank page and right click anywhere and select Buttons & Switches => Button. This is the
button we will use to initiate the pop-up. Right click your button and select Properties. Main TabText: Keypad Action TabAction: Quick Sequence Sequence: Component.EditBox.strContents = "" Page.Keypad.PopupModal() Leave all else to defaults Click OK Note: For this component to work you need to rename the page with your buttons and edit box to Keypad. To do this right click on this page in the Workspace and select Page Properties. Also, uncheck the box that says Initial Page? . Check this box on the page where you created the Keypad button in Step 8.
VIII
210
211
Legend: If you specify some text for a legend for a trace, a legend will be displayed with your graph. The location
of the legend is specified on the General sheet.
Trace Color: You can make a trace any color, or even colorize it based on an expression. To change the color,
simply click on the current color of the trace and the MutliColor Picker dialog will be displayed. We'll discuss how to set this up for displaying a multicolor trace a little later. To display the trace in a single color, simply double click on the current color displayed in the first row of the table and select the desired color from the color dialog that appears.
Line Type: Select the desired line type to be used to display the trace. This is only applicable when the axis is
set to display a line.
Point Type: Select the desired point type to be used to display the trace. This is only applicable when the axis
is set to display points.
212
the top and bottom sides of the rectangle are drawn in purple. You can freeze an axis manually, or restore / thaw an axis by right clicking on the graph and selecting Freeze / Thaw then selecting the desired axes. Thawing a particular axis will cause the scaling to revert back to the settings in the properties box. Freezing the X axis on a time graph manually can often be handy when you want to stop the constant march of your data across the graph, and is especially useful in this situation when using markers. If you like your new scaling and would like to set the scaling properties of an axis to what is displayed, you can open the axis sheet and press the Copy from Zoom button. This will make the scaling match the current max and min values of the axis. Note that this will overwrite any complex expressions you may have entered for these parameters. DAQFactory provides one other zooming feature that does not affect the freeze / thaw status of the graph. This is Zoom In Time and Zoom Out Time. You can access these options from the same menu as the other zooming functions. These work just like Zoom In / Out Horiz, except that on a time graph, these functions do not freeze the graph, but instead change the Time Width parameter directly.
New Name: If you would like to rename your axis, simply replace the default name with your new name. The
axis list and any traces assigned to this axis will automatically be adjusted.
Axis Label: This is the label that is displayed along the axis. Depending on the size of your graph, you may find
it easier to read axis labels if you put a space between each character.
Plotting Method: Each axis can have one of a variety of plotting methods. All traces assigned to an axis will
use the same plotting method. Some plotting methods are only available on left axes. The various methods are pretty self-explanatory, so we invite you to simply try them. Some methods may not work well with all data sets. Again, experiment.
Right Axis: This is a read only field. It indicates whether the axis will be displayed on the left or right side of the
graph. This may seem extremely obvious considering the default names of the axes, but if you rename all your axes, things may get less obvious.
Axis Color: This determines the color of the axis and scaling labels. Click on the current color to open the color
selection dialog box and select a new color.
Style: You can display any axis in either linear or logarithmic scaling. The bottom axis can also be displayed in
Date + Time mode, which will automatically display the time values in a more readable form instead of seconds since 1970. Note that if you try and set an axis into logarithmic scaling and the axis contains traces with illegal log values
213
Row: To create a stacked axis, simply assign a different row to each axis. If you would like to have stacked and
overlapped axes, assign the same row number to the overlapping axes.
% of Full Axis: Stacked axes do not have to have an even share of the vertical space of the graph. If you
leave this field at 100 for all the axes, then this occur. You can change this field to an appropriate percentage to make one stacked axis use more or less of the total space. If you change this field, all the values for this field for the axes in use should add up to 100.
Align. Thresh: For X vs Y graphs, you may often be plotting data taken at different time scales. DAQFactory
will perform an automatic alignment of your data in time just like the Align function. This parameter is passed to the Align function and determines how close two data points have to be in seconds to be considered to have the same time. If you want to disable this feature, set the alignment threshold to a negative number.
Auto Grid Control: If checked, DAQFactory will automatically set the grid line and tick spacing for you. If not,
you will need to specify spacing values in the next two fields.
Major Tick Spacing: The spacing of the major grid lines and ticks in the units of the axis. Minor Tick Spacing: The spacing of the minor ticks in the units of the axis. Full Length Minor Ticks? If checked, grid lines are displayed for minor ticks as well as major ticks. Area Graphs Negative from X Axis: Applies only if your Plotting Method is set to Area. If this is checked,
then the area graph will shade to 0. If not, then the graph will shade to the bottom of the graph.
Y Positive: An Expression that, when evaluated, determines the length of the positive going error bar in the Y
axis. The result should be in the units of axis itself. You can use a constant, or a complex expression. The result should be positive, or the error bar will be upside down.
Y Negative: Identical to Y positive, but applies to the negative going error bar in the Y axis. The result should be
positive, even though the error bar is going in the negative direction.
Y End Width: The width in pixels of the cap at the end of the Y error bars. X Positive: Identical to Y positive but in the X axis.
214
X Negative: Identical to Y negative but in the X axis. X End Width: Identical to Y end width but for X error bars. XY Box: All error bar expressions must be specified and valid for this feature to work. If checked, a box that
would outline the error bars with its center on the data point is displayed instead of the error bars.
End Thickness: The thickness in pixels of the end cap of all the error bars. Line Thickness: The thickness in pixels of the error bar lines (not including the end caps).
Axis Annotations:
Axis annotations appear as flags along the X axis to mark special events. They are designed for graphs displaying time along the X axis. The flags can have labels on them describing their purpose, and can be displayed in different colors. To create an axis annotation, open the Axis + Bound Annotations sheet of the graphs property box. The bulk of this sheet is taken up by the axis annotation table. Just like any other table in DAQFactory, use the Add and Delete buttons to add new rows and remove old ones. You can have as many different annotations as you need. Here is a description of the columns of the table:
Expression: The Expression for an axis annotation is a little unusual. Anywhere the result of the expression is
non-zero, the time of that point is flagged. For example, if your data looked like this {0,1,4,3,4,2} and you entered the Expression data = 4, then a flag will be placed at the time of the 3rd and 5th data points (where the data equals 4).
Text: The text that will be displayed with the flag. If either the expression or the text column are left empty, the
row will be deleted. If you don't want to display any text, enter a single space in the text column.
Color: The color of the flag and the text. Line Annotations:
Line annotations can be used to mark any value(s) on any axis. You can also use these to mark special events as well, but the expression format is a bit different. To create line annotations, open the Line Annotations sheet of the
215
graphs property box. This contains the line annotations table. You can have as many different annotations as needed.
Expression: The result of the Expression is used as the value along the desired axis for displaying the line. If
the result is an array of values, a line will be drawn at each of the values. If you want to mark special events along a time X axis similar to axis annotations, you will need to add a GetTime function to your expression (for example GetTime(data = 4)).
Text: The text that will be displayed along the line. If either the Expression or the text column are left empty, the
row will be deleted. If you don't want to display any text, enter a single space in the text column.
Axis: Select the desired axis that this line will be displayed along. The axis must have at least one trace assigned
to it. Line annotations assigned to the bottom axis are vertical lines, all others are horizontal.
Type: Select the type of line to display. Color: Select the color to display the line and the text. Bound Annotations:
Bound annotations display a shaded area along the top and / or bottom of the graph to denote areas such as noise floors or total dynamic range. These annotations can only be used if you have a single left or right axis, or you have a non-stacked left-right axis pair. To create a bound annotation, open the Axis + Bound Annotations sheet of the graphs property box. At the bottom, below the axis annotation table are the fields for creating bound annotations. Simply enter the desired text for whichever bounds you wish to display and the value to use. The lower bound will shade from the value down, and the upper bound will shade from the value up. To remove a bound annotation, simply erase the associated text. To display a bound annotation without any text, enter a single space in the text field.
General Sheet: Main Title: The title to be displayed along the top of the graph. Subtitle: A smaller title to be display along the top of the graph under the main title (if any). Legend Location: Where the legend should be displayed, if there is any to be displayed. A legend will only be
displayed if one of the traces has the Legend field specified.
Shadows: For a more fancy graph you can add shadows to your data points. This will slow down the generation
of the graph a bit, so you may want to save this feature for special occasions.
Point Size: The overall size of the points used with traces drawn with points. Graph Data Labels: If checked, then the X / Y coordinates of all the data points will be drawn next to the data
point. We suggest only using this if you have less than 50 data points or so. If you have more, you probably won't be able to read the data labels, and the graph will take a very long time to draw.
Line Gap Threshold: This specifies the distance two points need to be separated (in X) for a gap to be drawn.
Any less and a line will be drawn connecting the points. This obviously does not apply to traces drawn with Points only.
216
Display Gaps?: Determines whether gaps should be drawn between points separated by NaN's. Max Data Precision: The maximum precision used to display the axis scaling labels. Grid Axes: Which axes grid lines should be displayed. Grid Linetype: The type of line that should be used to display the grid lines. Grid in Front? Whether to draw the grid in front of the traces or behind them. No 1, 2, 5: Typically, DAQFactory will use an algorithm to display axis labels and grid lines at nice intervals. This
field allows you to turn off this feature.
Log Scale E Notations: Determines whether standard E notation should be used when labelling a log axis. Long Log Tick Threshold: Determines the point at which long log ticks should be displayed. Colors + Fonts:
Most of these parameters are quite self explanatory. Here are the few that are a bit less obvious. In general you will probably just want to play with these to get the desired results, since their effect on the graph depends on the size of the graph and the text that is being displayed.
Overall Font Size: Since the graphs can be resized at will, font sizes are not absolute, but relative to the
overall size of the graph. This parameter determines an overall scaling factor for all the fonts used to display the graph.
Overall Font Scaling: A more precise way to adjust the font scaling. Title Font Scaling: A separate scaling parameter for the title and subtitle. Legend Font Scaling: A separate scaling parameter for the legend. Axis Annotation Size: A separate scaling parameter for axis annotations. Unlike the other scalings, which are
relative to 1 and a change of 0.1 will result in a large change, this parameter is more coarse. A change of 10 will only be marginally noticeable. The default value of 50 will work for most cases.
8.11 X vs Y graphs
In DAQFactory you are not limited to value vs. time trend graphs. You can plot just about anything vs. anything else. Doing so is as simple as providing both a Y and X expression for the trace. Either can be a simple channel name, or a complex calculation. When both expressions evaluate to a value with time associated with it, DAQFactory will automatically align the Y data to the X data's time. In this way you can easily generate XY graphs on data taken at different time scales. If you wish to turn off alignment, set the Align Threshold to a negative number. The Align Threshold only applies to the bottom axis. Here are some things to think about when creating XY graphs If your data is randomly distributed in X then you will probably want to use the point plotting method, otherwise you will get a spaghetti of lines. If you provide a blank X expression for a trace, then the point number of the Y expression will be used for the X values. Even though there is only one X axis, each trace in your graph can have a completely different X expression. This is true on time graphs too. Because the Traces property tab uses the Y Expression to select which trace to edit, you must make sure each Y Expression is different. If you need to have the same Y Expression for multiple traces, presumably with different X 2011 AzeoTech, Inc.
217
Expressions, add something to make the expression different without changing the result. This can easily be done by adding an additional parenthesis pair, or doing +0, or something similar. Axis annotations only work if the X axis is displaying time, since they use the time of the data points to determine the flag location (though there are some ways around this using the InsertTime function). Markers don't work terribly well in XY graphs when the X data is randomly distributed. Sometimes when you move the markers with the keyboard, the markers can jump around unexpectedly. Since the graphs may be displaying constantly changing data, it is sometimes hard for the markers to get a lock on a data point. When using markers for ranging functions, especially Make NaN, remember that the range is determined by the X value of the two markers, not the data point number, but when making each point a NaN, it scans by data point number. Make NaN may work a little weird because of this, since it will start at the first point and scan through the data by point number until it finds a data point out of range.
Markers:
There exist 4 different markers for each graph within DAQFactory. The two standard markers are used for determining data point values and delta values between the two markers and can be used for ranging functions such as Make NaN and most analysis tools. The two peak markers enable you to quickly do a trapezoidal integration of a peak and also use a center-of-mass algorithm to take a quick guess at the peak location. To add any of the markers to a graph, right click close to the data point you would like to place the marker on, select the desired marker from the popup menu and select Add. from its submenu. To remove a marker, simply right click anywhere on the graph and select Clear from the marker's submenu. Once a marker is placed, data about the markers position will be displayed along the bottom of the graph. Peak markers only display their data once both markers are placed. You can move a marker once its placed using the keyboard. Make sure the graph with the markers is in focus. The left and right arrow keys will move Marker A, up and down arrow keys will move Marker B. Hold down the Ctrl key while pressing the arrow keys to move the peak markers.
Make NaN:
NaN stands for Not a Number and designates a data point with invalid data. The Make NaN function makes it easy for you to mark data as invalid while viewing that data on a graph. You can mark single data points or entire ranges, though for the range form to work properly, your X data must be sequential. X data is always sequential with time graphs. Make NaN even works on live data, effectively changing the history. Make NaN will not, however, affect the data being stored to disk by DAQFactory normally, but could affect local conditional logging. To make a single point NaN, simply put the Marker A on the desired data point and select Make NaN - Marker A from the graph popup. To make a range of points NaN, mark the first and last points with Marker A and B and select Make NaN - Range from the graph popup. The points the markers are on will be converted to NaN as well. If the trace you wish to apply the Make NaN contains a Y expression that references more than one channel, a dialog box will appear where you can select which channel you wish to apply the Make NaN to.
Analysis:
The graph popup offers direct access to the analysis boxes for analyzing traces. If a marker is on a trace, or if there is only one trace in the graph, the trace's expressions will automatically be inserted into the analysis parameters. If both Marker A and B are specified, then their locations can be used to specify the range of data to analyze. The data analysis tools are described in a later chapter.
218
Capture:
The capture function will create virtual channels with the data from the traces. If you choose to, this function can also make a new graph that references the new virtual channels. The new graph will essentially look like the old graph, but the data will be a static copy of the original data. Note that channels used for error bars, scaling parameters, or annotations are not captured. To capture a graph, simply select Capture from the graph popup. The capture box will appear with a list of all the traces in a table. Select the traces you would like to capture using the second column of the capture table. A default name is specified in the third column of the table. You are welcome to use this name, or you can simply change the name. At the top of the capture dialog box is the Create Graph? option. If checked, a copy of your original graph with the new virtual channels in it will be created on the scratch page. Note that the result of the expressions used to create the traces is captured, not the individual channels used in the expressions.
Export / Print:
Use this function to either export your graph to a Windows MetaFile, BMP file, or export the data that makes up the graph in ASCII text form. You can also use this function to print the graph. The options for these functions are fairly self explanatory.
Note: Error bars and markers will not be printed or exported. We suggest using a screen capture utility if you need to print or export these, or just print the entire Page. We are hoping in a future version to incorporate error bars into the exporting function.
219
ErrorBars: EndThickness LineThickness XEndWidth strXMinus strXPlus XYBox YEndWidth strYMinus strYPlus Windbarbs: strWindBarbDir strWindBarbLength strWindBarbSpeed
Axes:
There are 13 axes in every graph. To programmatically access their properties you have to reference their internal name which is fixed. This is different from their displayed name in the graph properties which is variable. The fixed names are LeftAxis1 through LeftAxis6, RightAxis1 through RightAxis6 and BottomAxis. To change an axis property, use the following notation: Component.graphname.axisname.propertyl Alignment AutoGrid strAutoScaleFrom AxisColor AxisTick GridDensity Inverted: this property is not available from the properties window. It inverts the scaling too, so it may take some fiddling with Scale From and Scale To to get the graph to display the way you want. strLabel LongTick NegativeFromX PlottingMethod: 0 = line, 1 = bar, 2 = stick, 3 = point, 4 = area, 8 = point + best fit line, 10 = histogram, 12 = bubble, 13 = point + best fit curve, 15 = point + best fit spline, 16 = spline, 17 = point + line, 21 = step, 22 = ribbon. Many of these are not available from the properties box. Other valid values exist up to 29, but may cause unpredictable results. PlottingStyle: 0 = linear, 1 = log, 2 = date/time Proportion: for stacked axes Row: for stacked axes strScaleFrom strScaleTo The bottom axis also has: strTimeWidth UseTimeWidth
General Settings:
BarWidth: for bar graphs DataPrecision DataShadows GraphDataLabels LegendLocation: 0 = top, 1 = bottom, 2 = left, 3 = right LineGapThreshold LogScaleExpLabels LogTickThreshold strMainTitle NULLGaps PointSize strSubTitle
Grids:
8 Graphing and Trending8.13 Graph variables and functions
220
GridInFront GridLineControl GridStyle: 0 = thin solid line, 1 = thick solid line, 2 = dotted line, 3 = dashed line NoGridLineMultiples
General Colors:
DeskColor GraphBackColor GraphForeColor ShadowColor TextColor
Font Sizes:
AxesAnnotSize FontSize FontSizeGlobal FontSizeTitle
Bounds:
strLowerBoundText LowerBoundValue strUpperBoundText UpperBoundValue
IX
222
Main:
Logging Method: Determines how the data is logged to disk. The choices are: ASCII: This is the default format that logs to a delimited ASCII files. Delimited ASCII files can be read by most every windows data analysis package such as Excel and so is a very flexible format. It is also easily opened and edited in other software packages, even notepad. Because of this, the file format can easily be repaired if some sort of damage was to occur to part of the file. This is the recommended format for logging your data, but has two disadvantages: 1) it consumes more disk space than the binary modes, and 2) it is reasonable slow. On our systems we can only log about 10,000 points per second in ASCII mode. Depending on your computer you may see better or worse performance. ASCII is also slow to load. If you have large data sets and are using a program that can load binary data, we suggest binary data format instead. ODBC Database: This format will log to an ODBC compliant database. How to set up an ODBC database is described in a separate section. ODBC is convenient if you ultimately want your data in a database, but it is very slow, especially when logging directly to Microsoft formats such as Excel and Access. We see 20 rows per second maximum update rates for these formats. You may see better performance, especially if you are writing to a native SQL database.
223
Binary: There are three different binary modes. Each uses a different binary representation for the data. If you are going to use your data in an application that can read a binary format we suggest this method over the other methods as it is very fast both to log and to load into your analysis software, and it is the most compact. The three different modes allow further fine tuning of the data set for most compactness and are discussed in a separate section. File Name: The path and filename you would like to log data to. Unless you have specified auto split files, this is the exact file name that the data will be logged to. Click on the Browse button if you want to use the standard Window's file selection window to select a file name. Data Source: This displays in place of file name when you select ODBC data base. This should be the name of the ODBC data source as defined in the ODBC manager. Note: This is NOT the name of the database! This has been a very common mistake despite our documentation so here it is again: THIS IS NOT THE NAME OF THE DATABASE SO IT SHOULD NOT BE A PATH TO A FILE! It should be the name you assigned in the ODBC manager. See the section on setting up an ODBC connection for more details. SQL: This becomes availble when you select ODBC database. Clicking this displays a window that allows you to adjust the SQL commands used. This is sometimes necessary as different database engines use different dialects of SQL. Table Name: This becomes available when you select ODBC database. This is the name of the table within the database where the data will be written. Channels Available / Channels To Log: These two tables determine what data will be logged. The channels available table lists all the channels in your channel table. Since logging sets do not support direct logging of variables or virtual channels, these will not appear in this list. Select the channels you would like to log either individually, or by holding the Shift or Ctrl key and selecting multiple channels, then move them to the channels to log table using the >> button. The All, None, Up, Down, and << buttons will help you get the exact list you want and in the proper order. In the channels to log table, there is an additional column called Figs:. This determines the number of significant figures that will be used when logging the data. This has no effect on binary formats, and may be limited in ODBC formats depending on your database. Manual: The manual button allows you to add additional columns to your logging set. This requires you to manually add data to the logging set through a sequence. Using this method you can log any sort of data in a logging set. Please see the section on logging set functions for more info. Two built in manual columns that can be added without writing a sequence is "Note" and "Alert" which will log any quick notes or alerts in with your data stream. Since notes and alerts are both strings, you cannot log these to a logging set using the binary logging method.
Details:
Mode: There are two different modes of logging. These are independent of the logging method and determine how data is collected and aligned to rows. All Data Points (aligned): This mode will log all data that comes in. The data is aligned to place data with the same or similar times on the same row. The spacing of the rows may be variable depending on when your data is acquired. Align Threshold: How close in time (in seconds) two data points have to be to be placed in the same row. Align Mismatch: If a particular column does not align with the current row's time, DAQFactory can either leave the value blank (or 0 for binary modes), or copy the last value written. Application: The All Data Points mode is useful when you want to make sure that every data point you acquire on the given channels is actually logged and no data massaging occurs before logging. Fixed Interval: This mode writes a row of data at a constant interval. The data written is either the most recent value for the particular column, or the average of the values acquired since the last row was written. Interval: Determines how often in seconds a row of data is written. Type: Determines what data is written. If average is selected, then the average of the data points that have arrived since the last row was written is used. If snapshot, then the most recent value of each column is used. Application: The fixed interval mode is useful when you are acquiring data at different rates but you want the final
224
logged data to be evenly spaced in time. Time Sig Figs: Determines how many significant figures are used to write time values. A value of 9 yields time precise to the second, 12 to the millisecond and 15 to the microsecond. The maximum value is 15. Use Excel Time: Internally, DAQFactory records time as seconds since 1970. This yields the best precision possible, and is the internal Windows standard, but is not the format used by Window's Office products like Excel. These products use decimal days since 1900. If you are going to be importing your data into Excel or other Office product, then data will be logged in a format that can easily be displayed. If you are not going to be using an Office product to import your data, then we recommend the DAQFactory format since it is in more convenient units of seconds. Include Time w/ All: If selected, then a time column is created for every data column. Otherwise, only a single time column is created. This is used when you wish to have close data on the same row, but need to know precisely when each data point was acquired. This only works in All Data Points Mode. Application: If you are using the All Data Points (aligned) with a threshold value other than zero, then it is possible for two data points with slightly different times (within the threshold) to be put on the same row and therefore be assigned the same time. If you want these points on the same row, but want to log the exact time of each point, check this option to create a separate time column for each data point. Log Unconverted Data: If checked, the data logged will not have any conversions applied to it. Application: This is a preference thing. It is certainly more convenient to log converted data. It saves you from having to convert the data after the fact. The problem is that many conversions are irreversible especially if you forgot what conversion you applied. By saving unconverted data, you always have the data in the rawest form and therefore should know what units it is in. Continue on Error: If checked and a file error occurs, the logging set will continue to retry logging data to that file. If not checked, then the logging set will stop if a file error occurs. Delimited By: Determines the delimiter used to separate values in the ASCII log mode. Enter "Tab" to use a tab delimiter. Include Headers: If checked then a single row of channel names properly delimited is written at the top of each file. This only applies for ASCII mode. For ODBC, the channel names are used for the field names. Header File: If checked, a separate file, with the same file name as the logging file, but with a .head appended is written describing the logging set. This is especially useful for binary logging methods which are completely useless if you forget what column is what or even how many columns you have. Auto Split Files: If checked, the logging files will be closed at a preset interval and a new file opened. A number is appended to each file name to properly organize all the files. Auto splitting files is most useful for long term acquisition to avoid large files and prevent data loss in the case of file corruption. Data File Size: Used if auto split files is checked. Determines the number of rows written per file. Use Date in File Name: Used if auto split files is checked. If this is checked, the date and time of file creation is used in determining the file number instead of simply numbering the files. Application: The auto split files option is designed for users who will be taking data continuously for long periods of time. By enabling this option, DAQFactory will create multiple sequential data files. This will keep you from ending up with a giant 20 gig data file. Auto split is also designed to help alleviate possible data loss from corrupted files. Very often, when a file gets corrupted, all the data in that file is lost. If you split your data into separate files, file corruption may be limited to a small chunk of your data.
225
2. On the main page, click on the Manual button. 3. Enter Note and hit OK. This will add note to the channels to log table. Now notes will be logged with the file. Alerts can also be logged by specifying Alert instead of Note. Both of these are strings so can not be used in binary mode logging.
226
This looks just like the User DSN and File DSN tab. System DSN's are available to all users on your system. User DSN's are only available to the user that created them. Creating the Data Source is identical for both. 3. Click on the Add button. You will then be prompted for a driver. This is the desired engine driver. Click on Finish when you find the one you need.
4. The next screen will differ slightly depending on the engine driver you selected. The first item is the Data Source Name. This is how you will reference the database within DAQFactory. Use some unique name. The rest of the items differ as mentioned, but typically there is a part that allows you to select the database file itself. There also may be some options that don't initially display. 5. Click on the Options>> button to expand them. For example, with the Excel engine, one of these options is Read Only which must not be checked otherwise DAQFactory won't be able to add any data!
227
6. When done, click OK and the data source is created. You can edit your data source by highlighting it in the list and clicking Configure. You are now ready to use ODBC within DAQFactory. To log to the database, select ODBC Database as the logging method in the logging set. Under Data Source enter the name of the data source (DSN) you created in the ODBC manager. Next, enter the name of the table within the database you would like to place the data. The table does not need to exist yet, and in general should not exist unless it was created by DAQFactory earlier. Important Note: A very common mistake is to put the path name to your database (c:\databases \mydatabase.mdb for example) in the box for Data Source. This is incorrect and will not work. DAQFactory does not need or want to know the name of your database file. All it wants is the name of the data source created in the ODBC administrator.
228
field name in the query results, plus two extra variables: FieldNames, which contains an array of strings listing all the fields of the query, and RecordCount, which contains the number of records returned from the query, which could be 0. So, for example, if you did: global myset = QueryToClass(dshandle, "SELECT Name, Address FROM myTable") then myset.FieldNames would equal {"Name","Address"}, myset.Name would contain an array containing the all the rows for the field Name, etc. For more advanced users using classes, you can provide an existing class instance (object) instead of having QueryToClass() create one for you. This allows you to use classes with member functions that presumably could work on the fields queried. So: myObject = new(MyClassType) QueryToClass(dshandle, "SELECT Name, Address FROM myTable", myObject) will create the same member variables (if necessary) as the other version of QueryToClass(), but will put them into myObject. Note that we provided the myObject instance and not the MyClassType class definition. The object must be instantiated already.
229
230
expressions instead of simple channel names. In this way you can subset data, or export calculated data. Creating and configuring an export set is almost the same as a logging set. There is only one table for specifying what gets exported. In this table, create a row for each field you would like to export. In each row, specify a name for the field (also used for the header in the ASCII logging method), an expression to log (i.e. MyChannel, or MyChannel / OtherChannel), and the number of significant figures to use. Note that the expression should ideally have a history as the length of the history determines the number of rows generated in your file. So, MyChannel[0] is probably not a good idea unless you just want one row. The export set details are very similar to logging sets. The difference is that export sets do not have auto splitting and have an option for whether an existing file should be overwritten or appended to. Logging sets always append to existing files. Application: One interesting way to use exports is to actually specify scalar values for the expressions (i.e. MyChannel[0]) and then use a sequence to repetitively start the export set. This will allow you to log any type of data, converted, calculated or otherwise. To do this: 1. Create a new export set. In this example we'll call it "WriteOne". 2. Add columns for each data point you would like to log. Each expression should result in a scalar value without history. Go to the details page and make sure its set to Append. 3. Create a new sequence: while(1) beginexport(WriteOne) wait(1) endwhile 4. Now when you run this new sequence, it will start your export set once a second, each time writing a single line of data. Application: You can extend the above application to log lines of data at particular events. Just call beginexport() whenever you want to write a line of data. Application: When doing batch runs where you start and stop logging with each new batch, there are two ways to log. One is to use logging sets of course, and simply start and stop the set at the beginning and end of the batch. But this does not give you the option to throw away the batch (and not log it). If you want to be able to run a batch and then optionally save to disk, create an export set for your data instead of a logging set. You'll want to clear the history of your channels at the beginning of the batch so you are not logging older data.
Variables: .strLoggingMethod: a string, either "ASCII Delimited", "ODBC Database", "Binary - 64 bit floating point",
"Binary - 32 bit floating point", or "Binary - 32 bit unsigned integers". This should not be changed while the set is running or unpredictable results will occur.
.strFileName: changing the file name while the logging or export set is running will close the current file and
open the new file. Application: if you are logging batch data and wish to start logging to a different file, simply set this variable to your new file name. You can use an edit box component or any of the components with actions, specifying Logging.
231
LoggingSetName.FileName as the action/set channel or use a sequence with assignment: Logging. LoggingSetName.FileName = "c:\newfile"
.strTableName: changing the table name while the logging or export set is running will switch logging to the
new table, creating it if necessary.
.AlignMismatchEmpty: 0 or 1 .AlignThreshold: numeric in seconds .AutoSplit: 0 or 1 .DataFileSize: numeric in rows .ExcelTime: 0 or 1 .IncludeAllTime: 0 or 1 .IncludeHeaders: 0 or 1 .strDelimiter: a string .LoggingAllValues: 0 or 1 .OverwriteExisting: 0 or 1. Not an option in the logging set view, but can be forced to 1 programmatically for
logging sets.
.RefreshRate: numeric in seconds. Determines how often the set writes buffered data. This should be 0 for
export sets otherwise the export set will repeat the export at the given rate. For logging sets this defaults to 1.
.Snapshot: 0 or 1 .TimeOffset: this value is added to the time columns in the logging set. This is used when working with MS SQL
databases. DAQFactory can use the time standard of Excel and Access, and for some reason, when using this format with MS SQL the time is offset by two days. Apparently a bug in MS SQL. You can therefore use this parameter to correct this bug.
.TimeSigFigs: numeric .CreateHeaderFile: 0 or 1 .LogUnconverted: 0 or 1 .AutoStart: 0 or 1 .Running: 0 or 1, read only. Functions: .Start(): starts the set. If the set is already started, nothing happens. .StartStop(): if the set is stopped, the set is started. If the set is started, the set is stopped. .Stop(): stops the set. If the set is already stopped, nothing happens
These functions are not applicable or available for export sets, and only apply to logging sets:
.ClearChannelList(): clears the list of channels to be logged. Usually you will call this and then the
AddChannel function to programmatically create a list of channels on the fly.
232
.AddChannel(name, [sigfigs]): adds a channel to the list of channels to be logged. Name is a string. Sig
figs is optional and defaults to 6.
.RemoveChannel(name): removes the given channel from the list of channels to be logged.
Application: The above three functions can be used to programmatically create a logging set. You could pretty easily create a way for the user to enter in channels to log at runtime. We do not recommend using these functions while the logging set is running. These functions are not applicable or available for logging sets, and only apply to export sets:
.ClearExpressionList(): clears the list of expressions to be exported. Usually you will call this and then the
AddExpression function to programmatically create a list of channels on the fly.
.RemoveExpression(Name): removes the given expression from the list of expressions to be logged.
Application: The above three functions can be used to programmatically create a logging set. You could pretty easily create a way for the user to enter in channels to log at runtime. We do not recommend using these functions while the logging set is running.
.AddValue(name, value): this function is used to manually add data to the logging set. First you must
manually add the column using the functions below or by clicking the Manual button in the logging set view. Then you can add data to this column by calling this function with that column name and the desired data. The data must have time associated with it as the time is used to determine which row the new data applies to. The time of the data points must be within the RefreshRate (1 second by default) of the current time or the data will appear in your file out of order. Application: The addvalue() function is used to add calculated data to your logging set. For example, let us assume that you have a channel X and a channel Y and you want to log X/Y in a column called Ratio in your logging set. To do this: 1. In your logging set, hit the Manual button, and enter Ratio. 2. Create a sequence: while (1) Logging.MyLoggingSet.AddValue("Ratio", X[0] / Y[0]) wait(1) endwhile 3. Now, when you run the sequence and the logging set, the ratio of X/Y will also be logged. Application: The problem with the above technique is that the time of the logging of the ratio is determined by the sequence, not the time X or Y was acquired. To make things more event driven, replace your sequence in step 2 above with an event assigned to either the X or Y channel: Logging.MyLoggingSet.AddValue("Ratio", X[0] / Y[0]) Now, the logging set gets the new value every time the channel that you applied the event to gets new data.
233
(C1122). File.Delete(filename): permanently deletes filename. Caution: You are not prompted to confirm! File.GetDiskFreeSpace(drive path): returns the amount of disk space remaining on the given disk. "drive path" can be any valid path on the desired drive. File.GetFileExists(filename): return 1 if filename exists, otherwise it returns 0 File.MakeDirectory(directoryname): creates the given directory. File.MoveFile(oldpath, newpath): moves the oldpath file to newpath. newpath cannot exist already or an error will occur (C1121). File.RemoveDirectory(directoryname): removes the given directory if no files exist in it File.Rename(oldname,newname): renames the oldname file to newname Application: All the above functions allow you to manipulate your files and monitor the file system. GetFileNameList(path): returns an array of strings containing the names of all the files matching the given path and wildcard. The name does not include the path. For c:\mydir\myfile.txt, the name is myfile.txt. GetFilePathList(path): same as above, but returns the whole path (c:\mydir\myfile.txt) for each file GetFileTitleList(path): same as above, but only returns the file title (myfile) for each file. Application: The above three functions are useful for retrieving a list of files. For example, if you wanted to open all the .csv files in a particular directory: Private.strPaths = File.GetFilePathList("c:\data\*.csv") if (IsEmpty(Private.strPaths)) return // if nothing found, we have to return for (Private.count = 0, Private.count < NumRows(Private.strPaths), Private.count++) Private.handle = File.Open(Private.strPaths[count],1,0,0,1) ... endfor FileOpenDialog([default file], [initial dir], [filter], [title]): all parameters are optional. This displays a standard windows dialog prompting the user for a file and returns the selected file path or an empty value (use IsEmpty() to determine) if the user cancels out of the dialog. This function can only be called by sequences running in the main application thread (a quick sequence action) FileSaveDialog([default file], [initial dir], [filter], [title]): same as above, but the user is prompted to save instead of open. Application: These two functions are great for giving the user a way to specify a logging file. Apply them to a button labelled "Set Logging File". Here is a sample Quick Sequence action that requests a file name and then sets the logging set "Log" to log to that name: Private.strFileName = FileOpenDialog() if (!IsEmpty(Private.strFileName)) Logging.test.FileName = Private.strFileName endif All the rest of the functions are for working on a single file, either reading or writing, and require a file handle which is returned from the File.Open() function. This handle should be kept and passed to all functions that are going to work on the file opened. This allows you to have multiple files open at the same time. The handle returned provides a way to track which file you are working on. For example: Var.FileHandle = File.Open("myfile.txt",1,0,0,0) Var.strIn = File.Read(Var.FileHandle,10) File.Close(Var.FileHandle) This function opens myfile.txt and reads 10 characters from it. It is good practice to always close your files when you are done with them, but if you forget, DAQFactory will close all open files when you quit the program.
234
File.Open(filename,read,write,append,text): all parameters are required. This opens the given filename for manipulation and returns a handle to the file. Set the read, write, and append parameters to 1 or 0 depending on if you want to open the file for reading, writing, and if writing, if you want to append to or overwrite an existing file. If the file does not exist, the append parameter is ignored. The last parameter determines if the file is an ASCII text file or not. The Read and Write functions work differently for text files. If you have write = 1 and append = 1 then the file pointer is automatically put at the end of the file. Otherwise it is placed at the beginning. File.Close(handle): closes the given file. The handle is a number returned by the FileOpen() function. File.CloseAll(): closes all files currently open. This is most useful if you lose track of a file handle (for example, stored in a private variable in a sequence that stopped before it closed the file). File.Abort(handle): closes the given file ignoring any potential errors. File.Read(handle,number of characters): If the file is opened with the text parameter set to 0, this function reads the given number of characters from the given file. Note that less characters may actually be read if the end of file is reached. If the file is opened with the text parameter set to 1, then the number of characters parameter is ignored and the function reads until it finds a newline character. The newline character is not returned. This function always returns a string. The file must be opened with the read parameter set to 1. File.ReadDelim(handle, index, parse by, eol character, number of lines, [string]): This function allows the rapid reading of a delimited file such as the common files generated by DAQFactory logging sets. Parsing begins at the current file location, so if you have a header line, simply do File.Read(handle) to read the first line, putting the file location at the beginning of the second line. This function only works if the file is opened with the text parameter set to 1. This function will read the item specified by index, where 0 is the first item on each line, in a list parsed by parse by, and a line ended with eol character. This will be repeated for the specified number of lines, or if 0 is passed for number of lines, until the end of file is reached. If string is specified and is 1, the result will be an array of strings. Otherwise, each item will be converted into a number and an array of numbers is returned, with NaN's returned whenever an item cannot be converted properly to a number. You can specify a negative index to retrieve all items in one read, returning a 2d array. With larger files, it is actually slower to read the entire file at once than to read individual items one at a time. Example: if you had the file: 1,2,3,4 5,6,7,8 ReadDelim(handle,2,",",chr(10),0) would return {3,7} ReadDelim(handle,-1,",",chr(10),0) would return {{1,2,3,4},{5,6,7,8}} File.ReadInter(handle, offset, interval, number of characters, number of intervals): This function allows the rapid reading of a binary file containing interleaved data. It will jump to the offset byte of the file, then read the specified number of characters. It will then jump by interval bytes (from the beginning of the block) and read the specified number of characters again, repeating for the specified number of intervals. If the number of intervals is set to 0, it will read until the end of file is reached. Typically this function will be used in combination with the To. and From. function to convert a binary data file into actual numbers. The file must be opened with the text parameter set to 0. For example, let's say your file contains the bytes 0 1 2 3 4 5 6 7 8 9. If you did ReadInter (handle, 2, 4, 2, 2) you would get {{2,3},{6,7}}. You could then use, for example, the To.Word() function on the result to yield {770,1798} File.Write(handle,string to write): writes the given string to the file. Note that you must add any desired CR/LF characters unless the file is opened with the text parameter set to 1 in which case a newline character is added automatically. For a file opened with the text parameter set to 0, the string is written verbatim with nothing added. The file must be opened with the write parameter set to 1. File.WriteDelim(handle,{data}, delimiter, eol character): writes the given array of data to a delimited file with the specified delimiter and end of line character. This is basically the opposite of File.ReadDelim(). The file must be opened with the write parameter set to 1 and the text parameter set to 1. Example: File.WriteDelim(handle,{{1,2,3,4},{5,6,7,8}},",",chr(10)) would write this to the file: 1,2,3,4
235
5,6,7,8 File.Flush(handle): writes any cached data to disk. For performance reasons, windows keeps some data in memory until a large enough block can be written to disk. This forces windows to write whatever it has kept in memory to disk. File.Seek(handle,offset): jumps to the offset position from the beginning of the given file. Offset is in bytes and must be positive or zero. File.SeekRelative(handle,offset): jumps the given offset from the current location in the file. Offset is in bytes and can be positive or negative or zero. File.SeekToBegin(handle): jumps to the beginning of the file. This is the same as File.Seek(handle,0). File.SeekToEnd(handle): jumps to the end of the file. This is the same as File.Seek(handle,File.GetLength (handle)) File.GetLength(handle): returns the number of bytes in the given file File.SetLength(handle,new length): sets the given file to have a given length, truncating if necessary. File.GetPosition(handle): returns the current position in the file that data will be read or written. File.GetFileName(handle): returns the file name of the current file File.GetFileTitle(handle): returns the file title of the current file File.GetFilePath(handle): returns the full file path of the current file
Step 1: Go to Channels and Add a new channel that will be used to provide data
Channel Name: MyChannelName Device Type: Test I/O Type: A to D Chn #0 Timing: 1 This simply creates a channel with some sample data for us to use.
Step 2: Go to SEQUENCES and create a new sequence called WriteFile. Insert the code below.
// Open File and get handle Private FileHandle = File.Open("C:\myfile.txt",0,1,1,1) // Format string Private string strText = FormatTime(MyChannelName.Time[0]) + "," + DoubletoStr(MyChannelName[0]) // Write data to text file File.Write(FileHandle,strText) // Close the file File.Close(FileHandle)
Step 3: In the Workspace, go to Page_0 and add a button by right clicking on the page and selecting
Buttons&Switches => Button.
236
Right click on the button and select Properties. Give the button the following properties: Main TabText: Write File Action TabAction: Start/Stop Sequence Sequence: WriteFile Click OK This creates a button to start the sequence and therefore write a line to the log.
Step 4: Go to PAGES: Page_0 and click on the button once a second for several seconds and then go to the root
directory and verify the data written. The file written to, and the directory, was set by this function: File.Open("C:\myfile.txt",0,1,1,1) from Step 3. The 0,1,1,1 indicates how the file was opened. The 0,1 at the beginning means it was opened for writing. The 2nd "1" means any existing file will be overwritten, and the last "1" indicates the file is opened in text mode, meaning a carriage return / line feed is appended to each line written using Write(). The above method gives the most flexibility in how and when your data is logged. But, it does not allow you to log in binary format or to a database. For this, you will need to use a logging or export set. A logging set is designed to log data continuously, which isn't the goal of this sample, so an export set is the other choice. Continuing this example we'll show how to do the same thing with an export set:
Step 5: Go to Export: and add a new export set called ExportLine. Set the following properties:
Main TabFile Name: C:\myfile.txt Details TabMode: Fixed Interval Interval: 1 Type: Snapshot There are other settings you can use to tweak how the data is written. For example, the default in an export set is to put a header line at the top, to append to an existing file, and to use Excel time, which is decimal days since 1900. The sequence we created above does not create a header line, it overwrites any existing file, and it uses DAQFactory time, which is seconds since 1970.
Step 6: On the main tab of the export set, hit Add to add a new row. Enter MyData for the name, MyChannelName
[0] for the expression and 6 for Figs. This is a key step. You must specify [0] after MyChannelName. This indicates that you just want to export the most recent value and keeps the export set from exporting more than one line of data. Setting the export set in Fixed Interval mode is also required to generate a single line of data.
Step 7: In the Workspace, go to Page_0 and add a button by right clicking on the page and selecting
Buttons&Switches => Button. Right click on the button and select Properties. Give the button the following properties: Main TabText: Export File Action TabAction: Quick Sequence beginexport(ExportLine) Click OK This creates a button to start the export set and therefore write a line to the log.
Step 8: Go to PAGES: Page_0 and click on the Export File button once a second for several seconds and then go to
the root directory and verify the data written. Which method to use, file I/O vs Export Set really depends on whether you need to log to a database or in binary. If
237
you do, then you have to use an export set, otherwise file I/O gives more flexibility. Even if you are logging in ASCII mode, you may find export sets easier as they have a number of nice automatic features, like header lines, excel time, easy control of significant figures, etc.
9.10.2 Read a file and set an output channel from its data
This sample shows how to write data to a file one line at a time delimited by commas. It then shows how you can read that file and set independent outputs with the delimited data every 1 second.
Step 2: In the Workspace right click on SEQUENCES and Add a sequence called CreateFile. Copy the following
code into the sequence window. // Opens the file sets the variable FileHandle Private FileHandle = File.Open("C:\mydata.txt",0,1,0,1) Private Count Private string strString for (Count = 0, Count < 10, Count++) //Concatenates the inputs into a comma delimited string strString = DoubletoStr(SysTime()) + "," + DoubletoStr(MyChannelNameIn_0[0]) + "," + DoubletoStr (MyChannelNameIn_1[1]) // Writes the string to the file File.Write(FileHandle, strString) // Writes every 1 second delay(1) endfor File.Close(FileHandle) This sequence will open the file c:\mydata.txt and then every second for ten seconds write the current values of MyChannelNameIn_0 and 1. This does almost the exact same thing as a logging or export set running in Fixed Interval / Snapshot mode, except that it runs for only ten intervals. The file I/O part is straightforward. The file is opened and the handle saved in FileHandle. The 0,1,0,1 in the Open() function indicates that we are writing to the file and that we are in text mode. Once open, we use the Write() function to write each string to the file. Since we opened the file in text mode, a carriage return / line feed is automatically written with each line as well. Finally we close the file once we are done writing.
Step 3: Add another SEQUENCES called ReadFile. Copy the following code into the sequence window.
// Opens the file sets the variable FileHandle Private FileHandle = File.Open("C:\mydata.txt",1,0,0,1) Private string strIn while (1) // read a line strIn = File.Read(FileHandle) // This checks for an empty string if(strIn == "")
9 Data Logging and Exporting9.10 Questions, Answers and Examples9.10.1 Write data to a file from a sequence
238
// Breaks out if empty string break endif // This code Parses the String and sets the output channel MyChannelNameOut_0 = StrToDouble(Parse(strIn,1,",")) MychannelNameOut_1 = StrToDouble(Parse(strIn,2,",")) // Reads 1 second at a time delay (1) endwhile // Closes the file File.Close(FileHandle) In this sequence, we read the file back in, one line at a time, one line each second. With each line, we separate the line and set the outputs. The separation is done by the Parse() function. So if the strIn was "102932435.324,2.423,5.392", then Parse(strIn,1,",") would return "2.423". Since this is still a string, we call StrToDouble() to convert it to a number, and then set our output by simply setting the channel to the value we read. The file I/O part is very similar to the write sequence. The file is opened, but this time we open it in read mode (by using 1,0,0,1 instead of 0,1,0,1). Since we open it in text mode, the Read() function will read a line up to the CR/ LF. Each read() returns a new line, or an empty string if the end of the file is reached. At the end, we close the file for proper cleanup.
Step 4: Add another SEQUENCES called StartUp. Copy the following code into the sequence window.
MyChannelNameOut_0 = 0 MyChannelNameOut_1 = 0 MyChannelNameOut_2 = 0 Check the Auto-Start box Click Apply & Compile This sequence simply sets the outputs to a default value of 0. This is not required for the functionality of this sample, but initializing outputs is a good habit to be in.
Step 5: In the Workspace select Page_0. Add a button to the page by right clicking on the page and selecting
Buttons & Switches => Buttons. While the button is still selected, right click on it and select Properties. Give the button the following properties: Main TabText: Make File Action TabAction: Start/Stop Sequence Sequence: CreateFile Click OK
Step 6: In the Workspace select Page_0. Add a button to the page by right clicking on the page and selecting
Buttons&Switches => Buttons. While the button is still selected, right click on it and select Properties. Give the button the following properties: Main TabText: Set Outputs Action TabAction: Start/Stop Sequence Sequence: ReadFile Click OK In the above two steps, we created new screen components to trigger the sequences we created. Buttons aren't really the best choice for triggering sequences since they don't tell us the current state of the sequence. For a sequence that would run quickly and stop, this is not an issue, but our sequences here will take 10 seconds to run. This does, however, show that you can use many different components to do different actions. In this case, a Variable Text component would be a better choice. When using the Variable Text component, all you have to do is click on the Quick - Sequence Trig button on the main page and select your sequence and all the other properties will be set for you.
239
Answer:
No: Excel Time: Decimal days since January 1, 1900. DAQFactory Time: Seconds since January 1, 1970. These are both local time, not UTC. To convert: ExcelTime = (DAQFactoryTime / 86400) + 365*70 + 19 DAQFactoryTime = (ExcelTime - 365*70 - 19) * 86400 As a side note, windows uses DAQFactory time internally for most things. Also, Excel time does not offer the same microsecond precision that DAQFactory time does.
Answer:
There are two ways. The first, and more flexible is to use Direct File Access functions to do all the logging, but with the flexibility comes additional work, so we'll explain the easier way which is to use an export set. In your export set, put the names of the channels you want to log and make sure to follow them with [0]. This will cause the export set to only write the most recent values for your channels. Then, on the Details page of the export set, select "Fixed Interval" and Type = "Snapshot". Now, whenever you start the export set a single line of data will be written. So, assuming you've created this export set, to trigger when your channel is greater than 3 you should use the event of the channel. Click on the name of the channel in the workspace to display the channel view, and then click on the Event tab. The Event is sequence code that gets executed whenever a new value is read or set on this channel. Put in something like this: if (MyChannel[0] > 3) beginexport(MyExport) endif This assumes, of course, that the channel name is MyChannel, and the export set is MyExport.
Answer:
You need a basic script to this:
9 Data Logging and Exporting9.10 Questions, Answers and Examples9.10.3 DAQFactory / Excel Time
240
// get the current month and year: private curmonth = StrToDouble(FormatDateTime("%m",SysTime()) private curyear = StrToDouble(FormatDateTime("%y",SysTime()) private date // loop forever: while (1) // set for retrieving time from year/month: date = Evaluate(Format("%dy%dm1",curyear,curmonth)) // set logging file name: Logging.MyLogging.strFileName = "MyData_" + FormatDateTime("%y_%m.csv",date) // now wait until the first of the next month: curmonth++ if (curmonth > 12) curmonth = 1 curyear++ endif // get time for next month date = Evaluate(Format("%dy%dm1",curyear,curmonth)) // wait until then waituntil(date) endwhile It looks worse then it really is. In the first couple lines we are using a the FormatDateTime() function to pull out the year and month number from the current time. We then figure out the DAQFactory time (seconds since 1970) representation of the first of this month. Next, we set the logging set name with the year and month. Next we increment the month and if its more then 12, do the year as well. Next we again convert next month into DAQFactory time, and finally wait until that time arrives. You would probably want to put this in its own sequence and mark it as Auto-Start, then it will run automatically and you can just forget about it. You'll still need to start your logging set for this to work properly, which you could do here by just adding "beginlogging(MyLogging)" at the top. Note, to do the same thing but every day or every hour requires a slightly different technique described in the next section. You can do it using this technique, but when you increment the day, you have to check the month, and then the year as well. To do this every hour, twice a day or other options, please see the section on doing things on the hour.
Answer:
You need a basic script to this. // loop forever: while (1) // wait until 11:59pm waituntil(23h59m) // wait another minute to move us into tomorrow delay(60) // set logging file name: Logging.MyLogging.strFileName = "MyData_" + FormatDateTime("%y_%m_%d.csv",SysTime()) // and repeat endwhile Its a bit different than the previous example of creating a file every month because hms time notation without any date information defaults to the current date. So, when we do waituntil(23h59m), DAQFactory waits until 11:59pm today. However, if we did waituntil(1d23h59m), it would return immediately almost always, because it would be waiting until 11:59pm on January 1 of this year, which, unless it was January 1st, had already passed. So, in this sequence, we wait until 11:59pm, then we delay another minute to get us into tomorrow, then we set the logging
241
name with tomorrow's (now today's) date. We can't simply do waituntil(0h) because that waits until midnight today which has already passed. You would probably want to put this in its own sequence and mark it as Auto-Start, then it will run automatically and you can just forget about it. You'll still need to start your logging set for this to work properly, which you could do here by just adding "beginlogging(MyLogging)" at the top. Note, to do the same thing but every month requires a slightly different technique described in the previous section. To do this every hour, twice a day or other options, please see the section on doing things on the hour.
9 Data Logging and Exporting9.10 Questions, Answers and Examples9.10.6 Changing the logging file name every day
10 PID Loops
10 PID Loops
243
10 PID Loops
10.1 PID Overview
PID is a common algorithm for process control. It is used to keep a process variable, such as temperature, set at a certain set point by controlling an output variable. PID is made up of three parts, proportion (P), integral (I), and derivative (D). There are many good books on PID and recommend reading them for more information on PID control. This chapter describes PID control within DAQFactory and assumes a basic understanding of the algorithm, at least its uses and the meaning and effect of the three terms. Within DAQFactory you can create as many PID loops as your computer will handle. Each loop runs in a separate thread within DAQFactory. A thread is like a separate program running concurrently with other threads running within DAQFactory. You can stop and start loops as necessary, independent of each other. Each PID is a standalone object and so whether using one PID loop or many, the process is the same.
PID parameters: Process Variable: an expression that when evaluated is used in the loop. This should be a singular value, i.e.
PV[0] DAQFactory automatically does a 4 point weighted average to reduce the effects of noise. You can add to this by doing a mean: Mean(PV[0,9])
Set Point: an expression that when evaluated is used as the target for the process variable. This should also be
a singular value. If you want this adjustable from a screen, use a variable, v channel or test channel.
Output Channel: a channel or variable name to set the result of the PID. P, I and D: These take numeric values for the three parameters that make up a PID loop. I and D are in minutes.
A value of 0 for I and/or D disables this part of the calculation, even though the I term is used in the denominator.
PID Type: There are two PID algorithms available. The standard algorithm applies the Gain to all three parts of
the calculation, thus Out = P * (e + i/I - D*dPV). The alternate, "separate" algorithm, keeps the gain solely in its own section, thus Out = P*e + i/I + D*dPV. This is a less standard algorithm, but tends to be much easier to tune because each term is independent.
SP Range: holds the possible range of set points and is used to help scale the output of the PID calculation. Out Range: limits the output to a certain range of values Loop Interval: how often the PID is calculated and the output channel is set. This should not be below 0.01
without a multi-processor system. Smaller values use up larger amounts of processor time.
Integral Limit: limits the accumulated integral to +/- this amount. This is an easy way to avoid integral windup.
Reverse Acting: if checked, then a negative output results in a positive moving process variable. Reset on SP change: if checked, then the accumulated integral and internal process variable and derivative
smoothing is reset whenever the set point changes.
244
Reset on Start: if checked, then the accumulated integral and internal process variable and derivative
smoothing is reset whenever a loop is restarted. Otherwise, the integral will continue to accumulate while the PID is stopped. The integral will not start to accumulate until the PID is started for the first time.
10 PID Loops
245
trace is your set point, the red trace is the output from the PID loop, and the green trace is the process variable. At this point feel free to play around a little with some of the parameters. You do not have to stop the loop to adjust the parameters. Remember though that the simulation is very basic, so autotuning will not really work on it. As you gain experience with sequences, you may want to play with the simulation and try and improve it.
10.3 Autotuning
PID support includes autotuning, which helps determine the best P, I, and D parameters for your particular process. To use, you must have your system in a stable state, with the process variable sitting close to the set point. Once there, select a relay height, which is the amount the output will be adjusted depending on whether the process variable is above or below the set point. Unlike PID control, the output just alternates between these two values. Press the start key to start the autotune. The system will need to go through at least two cycles, at which point it can calculate P, I, and D parameters. Ideally you should wait until the period and height of the process variable stabilizes. At this point (or any other point) you can use the Use Results button to copy the results of the autotune into the P, I and D fields. You will then need to apply the changes to keep the new parameters. Note: the big advantage of relay autotuning over other methods is that your system does not need to be taken far out of range to autotune. You can and should specify a very small relay height to keep your system within acceptable parameters. It is best to start with a very small and relay height and work up to ensure that you do not accidentally drive your system into an unacceptable range. Example: If you want to see autotuning in action, though perhaps not showing its true power, create the simulation system example described in the Creating a PID loop section. Then: 1. Make sure both the sequence and the PID loop are running. Go to the PID view for the PID loop and select the AutoTune page. 2. The autotune page also shows a graph. If you recently changed the setpoint, wait until the process variable stabilizes close to the setpoint. 3. Enter a relay height of 2, then click Start to start the autotune procedure. What you will see at this point is the output red trace alternating between +2 and -2 relative to your setpoint as the process variable in green itself alternates above and below the setpoint. After two such oscillations, the Calced P, I and D values will be displayed. With every cycle, these numbers will change slightly as the autotuning zones in on the best number. When you are satisfied with the values, you can stop the autotuning and click Use Results to copy the values into the loop parameters. You will also have to click Apply to save these new values into the loop. Because the simulation is so basic, the autotune probably will not improve the loop much and may even make it worse. In a real system however, autotune can really help get you close to the ideal parameters.
- the normal output is the sum of these three parameters calcedSP - actual SP value (result of SP expression)
calcedPV - actual PV value (result of PV expression) You can optionally return an output value to use in place of the normal output value for this loop iteration. If you do so, the output range parameters of the PID are ignored. If you need to limit your outputs while using the event 10 PID Loops10.2 Creating a new PID loop
246
you'll need to do so in the event. For example: Private.out = (Private.effectP + Private.effectI + Private.effectD) + 2.5 if (Private.out > 5) Private.out = 5 endif if (Private.out < 0) Private.out = 0 endif DAC0 = Private.out
Variables: .P : numeric .I : numeric .D : numeric .SPMax : numeric .SPMin : numeric .OutMax : numeric .OutMin : numeric .ReverseActing : 0 or 1 .LoopInterval : numeric in seconds .HistoryLength : numeric. This determines the number of points kept in the PV, SP, and OV histories. The
default is 3600. If you don't need these histories, you may want to set this parameter to 1. In addition to programmatic access, the histories are used to generate the PID view graphs.
.AutoTune_P: read only numeric result of the autotune .AutoTune_D: read only numeric result of the autotune .AutoTune_I: read only numeric result of the autotune .StartAutoTune(height): starts up the autotune procedure with the given relay height. Height must be nonzero.
.StopAutoTune(): stops the current autotune procedure if running. Throws an error if the autotune is not
running.
.PVHistory: an array with the history of process variable values with time. Use subset notation to pull parts of
this array: .PVHistory[0]
10 PID Loops
247
.SPHistory: same for set point .OVHistory: same for the output variable
Answer:
There are two choices: With the standard algorithm, the gain applies to all three terms. It boils down to: effectP = P * error effectI = P / I * integral effectD = -1 * P * D * dPV There is some additional stuff to smooth out the error, derivative and other such items. If you want an ID only loop, just set P to 1, then do Out = effectI + effectD
With the separate algorithm, the gain only applies to the first three terms: effectP = P * error effectI = integral / I effectD = -1 * D * dPV
11 Alarming
XI
11 Alarming
249
11 Alarming
11.1 Alarming Overview
The alarming features in DAQFactory allow you to watch for certain alarm events. When an alarm event occurs, the alarm is said to have fired. Once fired, it will show up as an active alarm in the alarm summary view. Alarms remain active until a reset condition occurs at which time they are reset. Even when an alarm resets it still must be acknowledged for it to stop displaying in the alarm summary view. In this way if a part of your system goes out of bounds for a short time when you weren't watching, you will still see this as an alarm. Alarm events are logged to disk either as an ASCII file or in an ODBC database. Alarm events can also trigger sequence events to perform other actions when an event occurs. Alarming is only available in the pro version of DAQFactory.
Alarm Parameters: Condition: when this expression evaluates to a non-zero number then the alarm fires. If an alarm sound file is
specified, it will be played. This is evaluated for every incoming data point, but does not evaluate streaming, or image data. Data added to a channel using the AddValue() function will also cause alarms to be evaluated.
Reset Condition: when this expression evaluates to a non-zero number and an alarm has fired, the alarm is
considered reset. The alarm will still sound until acknowledged.
Description: description displayed in the alarm table view Priority: determines the color and order alarms are displayed. Log only alarms do not display in the alarm table
and are simply logged. They also automatically acknowledge.
Alarm Sound: a wave file that is played continuously until the alarm is reset and acknowledged or another alarm
with a sound fires.
Enabled: determines if the alarm is evaluated Help: extra information about the alarm Events: Alarms also have three events, sequence steps that will be executed when a particular event occurs.
There is one for when the alarm fires, when the alarm resets, and when the alarm is acknowledged. Each has its own tab in the alarm view. If you return(0) from the event, then the alarm fire, reset or ack will be ignored.
250
Application: One possible use for the alarm event is preventing a user who needs to see a list of alarms from acknowledging them. The alarm summary view has an Acknowledge All button, which cannot be disabled. You can however, still prevent the user from acknowledging the alarms. To do this, simply create an ack event for each alarm. In that event do the following: if (Var.AlarmRights == 1) return (1) else return (0) endif Then, create a way for the user to login, and in the process set Var.AlarmRights to either 0 or 1 depending on whether they are allowed to acknowledge the alarms. This can of course be applied on an alarm by alarm basis, allowing different users the ability to acknowledge only certain alarms. Hint: You could also code the above event as: return (Var.AlarmRights == 1)
11 Alarming
251
Variables: Alarm.FiredCountAdvisory : returns the total count of Advisory alarms fired and not acknowledged. Alarm.FiredCountCritical : returns the total count of Critical alarms fired and not acknowledged. Alarm.FiredCountLog : returns the total count of Log alarms fired and not acknowledged. Alarm.FiredCountTotal : returns the total count of all alarms fired and not acknowledged. Alarm.FiredCountWarning : returns the total count of Warning alarms fired and not acknowledged. Alarm.strLatestAlarm : returns the name of the last alarm to fire. Alarm.LatestAlarmColor : returns the default color, based on the priority, of the last alarm to fire. Alarm.LatestAlarmAcked : return 0 or 1 on the acknowledge state of the last alarm to fire. Alarm.strLatestLogAlarm : returns the name of the last alarm with LogOnly priority level to fire. Alarm.LatestLogAlarmAcked : returns 0 or 1 on the acknowledge state of the last LogOnly priority alarm
to fire.
Alarm.strLatestAdvisoryAlarm : returns the name of the last alarm with Advisory priority level to fire. Alarm.LatestAdvisoryAlarmAcked : returns 0 or 1 on the acknowledge state of the last Advisory priority
alarm to fire.
Alarm.strLatestWarningAlarm : returns the name of the last alarm with Warning priority level to fire. Alarm.LatestWarningAlarmAcked : returns 0 or 1 on the acknowledge state of the last Warning priority
alarm to fire.
Alarm.strLatestCriticalAlarm : returns the name of the last alarm with Critical priority level to fire. Alarm.LatestCriticalAlarmAcked : returns 0 or 1 on the acknowledge state of the last Critical priority
alarm to fire.
Alarm.Paused: this will pause the checking of alarms. If you have a lot of alarms, your acquisition loops can be
slowed because all alarms are normally checked every time a new value comes in. To give you control, you can pause the alarm checking while you acquire data in your loop, and then resume it when done. Use this in conjunction with the Alarm.CheckAlarms() function below. There are typically two ways you can implement this: 1) You can pause alarm checking in an auto-start sequence, leaving it paused, and then manually check alarms. This is probably the preferred way. You can either create a separate sequence to check alarms at a fixed interval, or put the CheckAlarms() at the end of your polling loop. 2) You can pause alarm checking while acquiring data in a polling loop and then unpause and check alarms after completing the loop. This is typically done with acquisition done with function calls and the AddValue() function: try Alarm.Paused = 1 ... Acquire data and call addvalue() to put it into channels... Alarm.Paused = 0
252
catch() Alarm.Paused = 0 endcatch Alarm.CheckAlarms() You'll want to use the try/catch block to ensure that Alarm.Pause gets set back to 0 in case of error.
Alarm.ResetCountAdvisory : returns the total count of Advisory alarms reset and not acknowledged. Alarm.ResetCountCritical : returns the total count of Critical alarms reset and not acknowledged. Alarm.ResetCountLog : returns the total count of Log alarms reset and not acknowledged. Alarm.ResetCountTotal : returns the total count of all alarms reset and not acknowledged. Alarm.ResetCountWarning : returns the total count of Warning alarms reset and not acknowledged. Functions: Alarm.AckAllAlarms() : acknowledges all alarms. This is the same as clicking the Acknowledge All button in
the alarm summary view.
Alarm.Ack(Alarm Name) : acknowledges the given alarm only. For example: Alarm.Ack("MyAlarm") Alarm.CheckAlarms(): manually checks all alarms. Alarms are normally checked whenever a new data point
arrives on any channel. You can also trigger the checking of alarms manually using this function. This is typically used with the Alarm.Paused variable. Individual alarms also have variables. Most correspond directly to the parameters of the alarm. All of them start with Alarm.AlarmName. where AlarmName is the name of the alarm.
Variables: .strCondition : a string containing the expression .strResetCondition : a string containing the expression .strDescription : a string with the description .strHelp : a string with the help information .Enabled : 0 or 1 .strSound : a string with the path to the .wav file .TimeFired : the last time the alarm fired. .TimeReset : the last time the alarm was reset. This resets to 0 when the alarm fires. .TimeAcked : the last time the alarm was acked. This resets to 0 when the alarm fires. .Fired : 0 or 1. If 1, then the alarm has fired, but hasn't been reset. .Acked : 0 or 1. If 1, then the alarm has fired and been acked.
For the above two parameters: Fired = 0, Acked = 1: alarm is enabled, but off. Fired = 0, Acked = 0: alarm has fired and been reset, but not acked.
11 Alarming
253
Fired = 1, Acked = 0: alarm has fired but not reset nor acked. Fired = 1, Acked = 1: alarm has fired and been acked, but not reset.
Step 1: Create a new test channel. Go to CHANNELS: located in the Workspace and Add a new channel with the
following Properties. Channel Name: Input Device Type: Test D#: 0 I/O Type: A to D Chn #: 0 Timing: 2 Offset: 0 Click Apply This just creates some generic data to trigger the alarm. Test A to D channels create a sine wave.
Step 2: Create the Alarm: Go to ALARMS: located in the Workspace and Add a new Alarm called GreaterThen with
the following Properties. Main TabCondition: Input[0] > 0.98 Reset Condition: AlarmReset Reset Event tab: add this sequence script: AlarmReset = 0 Click Apply This creates an alarm that will trigger when the Input channel is greater than 0.98. It will remained Fired until the variable AlarmReset is set to a non-zero value. The Reset Event is script that executes when the alarm is reset. In this case, we set the AlarmReset variable back to 0 to keep the alarm from resetting immediately the next time it fires.
Step 3: Create a Sequence. Go to SEQUENCES: located in the Workspace and Add a new Sequence called StartUp
. Copy and paste the following code into your sequence view. global AlarmReset = 0 // This code allow us to reset the variables only once. if(Alarm.GreaterThen.Fired) AlarmReset = 1 endif // Call the function to acknowledge all alarms Alarm.AckAllAlarms() This sequence simply initializes the AlarmReset variable and acknowledges any alarms. This gives us a good starting point.
Step 4: Go to a blank page and right click anywhere and select Buttons & Switches => Button. While the button
you just created is still highlighted hit Ctrl-D to Duplicate it for a second button. Right click the buttons and give 11 Alarming11.5 Alarm Variables and Functions
254
them the following Properties. Main TabText: Reset Action TabAction: Quick Sequence Sequence: Copy and paste following code if(Alarm.GreaterThen.Fired) AlarmReset = 1 endif Click OK This component will reset the alarm by setting the AlarmReset variable to 1. The if() statement keeps us from resetting the alarm before it is fired. Alarm.GreaterThen.Fired will return 1 (true) if the alarm has triggered. Main TabText: Acknowledge Action TabAction: Quick Sequence Sequence: Copy and paste following code Alarm.Ack("GreaterThen") Click OK This component simply acknowledges the GreaterThen alarm.
Step 5: Right click on a blank area of your page and select Displays => Variable Value. Hit Ctrl-D to Duplicate this
component three times for a total of four components. Go to the Properties of each and enter as follows. Main TabCaption: Channel Input Expression: Input[0] Click OK Next component: Main TabCaption: Time Fired Expression: FormatDateTime("%c",Alarm.GreaterThen.TimeFired) Click OK Next component: Main TabCaption: Time Reset Expression: FormatDateTime("%c",Alarm.GreaterThen.TimeReset) Click OK Next component: Main TabCaption: Time Acknowledged Expression: FormatDateTime("%c",Alarm.GreaterThen.TimeAck) Click OK These components simply display the current value and the times of various alarm events. FormatDateTime("% c",...) will format a DAQFactory date/time into a string using the date/time format for your locale (i.e. month / day / year for the U.S.). Alarm.GreaterThen.TimeFired and the others are simply variables of the GreaterThen alarm that hold the DAQFactory date/time of that particular event, or 0 if it has not occurred yet. 2011 AzeoTech, Inc.
11 Alarming
255
Step 6: Right click on a blank area of the page and select Displays => Symbol. Go to the Properties and enter as
follows. Main TabExpression: Alarm.GreaterThen.Fired Color TabBackground Color Threshold: 0, Color: Green Threshold: 1, Color: Red Size TabBlink: Expression: !Alarm.GreaterThen.Acked Click OK This component displays the fired state of the alarm by using the Fired variable of the alarm. As mentioned before, the Fired variable will return 1 if the alarm has triggered, and 0 if not. The background color table will therefore show green when the alarm is not triggered (0), and red when it is (1). Likewise, it will blink when the alarm has not been Acked. Acked gets set to 1 when you acknowledge the alarm, and is reset to 0 when the alarm fires.
Step 7: Right click on your sequence StartUp and select Begin Sequence. Verify that your program works. Use the
Reset and Acknowledge buttons to reset the alarm.
12 Networking / Connectivity
XII
12 Networking / Connectivity
257
12 Networking / Connectivity
12.1 Networking overview
DAQFactory can directly and easily connect to the DAQConnect service (see www.daqconnect.com) allowing you to view your data in real time (at least Internet real time) from a browser any where in the world without having to put the DAQFactory system on the Internet or open up your firewall or router settings. This provides a much more secure solution than allowing external Internet traffic to your DAQFactory system and eliminates the need to be an IT expert or get your IT personnel involved. It also limits the processor load on the DAQFactory system when you have multiple users viewing your data remotely. DAQFactory also has the ability to send emails, optionally with attachments. Emails can be sent out at any time with any message. This can be used to email you a daily status, or email when an alarm occurs. You can even have DAQFactory email you your data every day. DAQFactory can act as a DDE server allowing you to pass data in real time to a DDE client program such as Excel. DAQFactory DAQFactory DAQFactory connections uses the Internet standard TCP/IP to communicate between copies of DAQFactory. Networking in is as simple as pointing DAQFactory to another copy of DAQFactory. The connection between and other copies of DAQFactory are called, appropriately enough, a connection. You can have as many as you need within DAQFactory to communicate with multiple copies of DAQFactory at the same time.
DAQFactory can directly and easily connect to the DAQConnect service (see www.daqconnect.com) allowing you to view your data in real time (at least Internet real time) from a browser any where in the world without having to put the DAQFactory system on the Internet or open up your firewall or router settings. This provides a much more secure solution than allowing external Internet traffic to your DAQFactory system and eliminates the need to be an IT expert or get your IT personnel involved. It also limits the processor load on the DAQFactory system when you have multiple users viewing your data remotely. If you do not wish to use DAQConnect you can use the Page. Capture() functions and an external web server. DAQFactory supports the use of TAPI compliant modems for outgoing and incoming calls. When used with the SAPI speech engine, you can read or interpret speech over the phone line to announce alarms, settings, etc. or process commands. Detection of tones is also possible. DAQFactory also has the ability to send emails, optionally with attachments. Emails can be sent out at any time with any message. This can be used to email you a daily status, or email when an alarm occurs. You can even have DAQFactory email you your data every day. Finally, DAQFactory also can act as a DDE server allowing you to pass data in real time to a DDE client program such as Excel.
258
DAQFactory document will be linked to it. Note: if you are using a proxy to get to the Internet or a dedicated instance of DAQConnect (i.e. you access DAQConnect through a URL other than www.daqconnect.com, please see the Settings section below before you you do Connect... To then send data to DAQConnect, you simply mark the desired channels for sending: 1) Go to the channel table by clicking CHANNELS in the workspace. Towards the right of the table you'll see three columns related to DAQConnect: DAQConn?, determines if the channel data is being sent to DAQConnect. Check this box to mark the channel. DC Hst:, determines how many data points are kept on the DAQConnect server for historical viewing. This number is limited by the plan you select. You can enter -1 to have DAQConnect automatically apply an even amount to all of your tags based on your plan, or you can specify exact amounts for each channel allowing you to have more data retained for certain channels. DC Intvl: determines how often the channel data is sent up to DAQConnect. This is in data points. So, if you are taking data once a second and you put a value of 10 in this column, every 10th data point is sent. This is to allow you to take data at a faster rate than it is sent to DAQConnect. Please note that DAQConnect may limit the spacing of data points being sent to it. If you need to send high speed data such as streamed data, you should contact DAQConnect to arrange for a special plan. Once you click Apply in the channel table, DAQFactory will start sending the data to DAQConnect. You can go to DAQConnect, and in the Basics menu see your tags appear. You can then start creating your screens within DAQConnect to view your data from any browser. To change the data source you are sending data to, you can once again go to Real-time Web -> Connect.... You will be taken to a screen listing all your data sources on your account, highlighting the one you are currently connected to. You can then select a different data source.
Settings:
From Real-time Web -> Settings... you can adjust a couple settings for your DAQConnect connection: Display Detailed Status: checking this box will display detailed status information about your DAQConnect connection in the Command / Alert window. This is quite useful when you are first establishing a connection. This setting is not saved with the document as its designed primarily for debugging. Host: this setting should only be changed from www.daqconnect.com if you are using a proxy server or a dedicated DAQConnect instance. If using a proxy, set this value to the IP of the proxy. If using a dedicated instance (and no proxy), set this to the URL of your dedicated instance. Host Name: this setting should only be changed from www.daqconnect.com if you are using a dedicated DAQConnect instance. If so, you should set this to the URL of the dedicated instance.
12 Networking / Connectivity
259
if your channels are updating every 60 seconds, you can only possibly get commands from DAQConnect every 60 seconds. In these situations, you might consider using a Test channel or similar to ping the server more rapidly. 3) When the sequence is called, two local variables are created: "key" and "val". What these mean is largely up to your design. If, for example, you were directly controlling a digital output, "key" might be the name of a channel, and val either 0 or 1. In this case, you might use this script: if (key == "mydigout") mydigout = val endif If you wanted to do more channels, you'd just repeat, or use a switch/case instead. Now some important details: key is always lowercase, no matter how you specify it in DAQConnect, and will NOT include the data source name. This is stripped by DAQConnect. val is a string, but will automatically get converted to a number when setting numeric output channels. For other uses, you may need to use strtodouble() to convert it to a number in the above example we did no constraining or safety checks. Unless the output being controlled doesn't connect to anything dangerous, you should always do a safety check or ensure proper safeties are in place in hardware. Remember that the output could be controlled remotely, and you should assume it could change at any time, even if you think you are the only one with access. here's an example of a constrained output: private nVal = strtodouble(val) // convert to a number if (key == "myout") if ((nVal > 20) && (nVal < 40)) myout = nVal endif endif Note that we converted the string "val" to a numeric "nVal" before doing comparisons. > and < and other operators will work on strings, but work in a different way ("2" is actually > "10" for example, even though 2 < 10) the OnDCSet event should run fast. Do not put loops or delay()'s in this sequence. If you need to do a loop or delay, do it in another sequence started with beginseq() NOTE: if you lose your Internet connection or otherwise have troubles sending data to DAQConnect, the data will queue up until a connection can be reestablished. There is a hard limit of 10,000 data points per packet across all tags to ensure you don't run out of RAM. If more than 10,000 data points queue up while waiting for a connection, the packet will be cleared and all accumulated data will be lost. New data will then reaccumulate until the connection is established or the process repeats.
Email.strHost: the name of your smtp host. For example: Email.strHost = "mail.myISP.com" Email.strUserName: your smtp username Email.strPassword: your smtp password (optional) Email.strEncoding: the encoding of your message. Default is iso-8859-1 Email.strTo: the email address youd like to send the message to Email.strCC: the CC for the email
260
Email.strSubject: the subject of your email EMail.strFile: the full path to a file you would like to attach to the email Email.strReplyAddress: the email that shows up on as the reply. This is required. Email.strReplyName: the name that shows up as the reply Email.strBCC: the BCC for the email Email.strBody: the body text of the email Email.AutoDial: if you are on a dialup connection, set this to 1 to have DAQFactory dial your ISP when the
email is sent. Defaults to 0.
Email.Mime: set to 1 for Mime type attachment. Defaults to 0. Email.HTML: set to 1 for an HTML body. Defaults to 0. Email.Port: set to the port of your SMTP server. Defaults to 25. Email.strAuthenticate: can be one of three strings to determine the authentication method required for your
SMTP server: "NoLogin", "AuthLogin", "LoginPlain". If you do not require a password, use the first (the default). Usually if you do require a password you will use AuthLogin, but if that does not work you can try LoginPlain.
Email.Send(): Once you have set the desired variables, call the Email.Send() function to actually send the
email. You can send multiple emails by simply changing the desired variables and calling send again. For example if you wanted to send yourself an email with some values every 12 hours, you could set all the initial variables once and then set the body only and call send every 12 hours.
POP3.strServer: the name of your POP3 server. For example: POP3.strServer = "mail.myISP.com" POP3.strUserName: your POP3 username POP3.strPassword: your POP3 password (optional) POP3.Port: set to the port of your POP3 server. Defaults to 110. POP3.Timeout: the connection timeout in milliseconds. This defaults to 60000, or 60 seconds.
Once these variables are set, you can use these functions to actually retrieve your emails. In general you will want to Connect(), retrieve emails, then Disconnect().
POP3.Connect(): call this function first once your variables are set for the proper server. This function will
connect to your server and retrieve the number of messages waiting. The function returns the number of messages waiting.
POP3.Disconnect(): when done, call this function to disconnect from the server.
Once you have connected and checked to see that their are messages, there four functions you can call on each individual message. Which message these functions apply is determined by the message number, which starts at 0 for the first message, and goes to 1 less than the number of messages returned by Connect(). 2011 AzeoTech, Inc.
12 Networking / Connectivity
261
POP3.RetrieveMessage(message number): retrieves the given message in its entirety. Use the
Get...() functions listed below to retrieve the various parts of the message.
POP3.DeleteMessage(message number): deletes the specified message from the server. POP3.RetrieveHeader(message number): retrieves just the header for the message. You can then
use the Get...() functions listed below to retrieve the details. Obviously the GetMessageText() and GetBody() functions won't return anything since the body is not retrieved by this function.
POP3.GetHeaderText(): gets the raw header text POP3.GetMessageText(): gets the raw message text POP3 Example:
Here's an example script that connects to a POP3 server, retrieves each message if the body size is less than 100,000 bytes, and deletes the message. pop3.strServer = "mail.myserver.com" pop3.strUserName = "[email protected]" pop3.strPassword = "mypassword" private count private size count = pop3.Connect() ? "found "+doubletostr(count)+ " messages..." while (count > 0) count-size = pop3.RetrieveMessageSize(count) if (size < 100000) pop3.RetrieveMessage(count) ? pop3.GetBody() endif pop3.DeleteMessage(count) endwhile pop3.Disconnect()
262
12.5 FTP
With DAQFactory you can FTP to remote servers and upload and download files. Use this to upload data files to a server to share, or even generate dynamic HTML with the File. functions and then upload them to your webserver. FTP is implemented like Email, using sequence steps and a collection of variables and functions. All these functions / variables begin with FTP.
FTP.strServer: the name of your FTP server. For example: FTP.strServer = "ftp.myISP.com" FTP.strUserName: your FTP username FTP.strPassword: your FTP password (optional) FTP.strLocalFile: the full path to the file you are uploading, or the place to put the downloaded file. FTP.strRemoteFile: the path on the remote server where you'd like the uploaded file placed, or the path to
the file you'd like to download.
FTP.Port: the port to use for FTP. This defaults to 21. FTP.Timeout: the connection timeout in milliseconds. This defaults to 3000, or 3 seconds. FTP.BytesTransfered: during the transfer, you can read this value to determine the progress of the transfer. FTP.BytesToTransfer: during the transfer, if available, this tells you how big the file to transfer is. FTP.Upload(): Once you have set the desired variables, call the FTP.Upload() function to actually start the FTP
Upload.
FTP.Download(): Once you have set the desired variables, call the FTP.Download() function to actually start
the FTP Download. Upload() and Download() run the FTP transfer asynchronously. This means the functions will return immediately. To determine the progress of the FTP transfer, use the BytesTransfered / BytesToTransfer variables. Note that you can only run one FTP transfer at a time and will receive an error if you try to do otherwise.
12 Networking / Connectivity
263
events are described below. One important general point is that these events run in the thread of TAPI, which is the main application thread, and not their own thread. This means that any event code should be fast or your user interface will become sluggish. If you need to do any slower processing, use beginseq() to start up another sequence in its own thread. All functions for communicating with a TAPI modem start with TAPI. With the exception of GetDeviceList() all functions run asynchronously and will always succeed. Any errors will display in the alert window and cannot be caught using try / catch. You will want to use the events described below heavily to determine what state the modem is currently in and when to execute subsequent commands. You can also use delay() to give a command time to execute, but this is less reliable. Before you can use almost all the functions you must call Init(): TAPI.Init("ModemName") This function takes the name of the TAPI device you wish to use. You can retrieve a list of available TAPI devices by calling GetDeviceList(): private string devlist = TAPI.GetDeviceList() This function returns an array of strings of valid TAPI devices. Note that these devices may be TAPI compliant but aren't guaranteed to work with the DAQFactory TAPI functionallity. You only need to call Init() once. We recommend delaying at least 1 second after Init() before calling any other TAPI functions. Once you have initialized TAPI, you can use the modem. At this point you will need to establish a call. You can either initiate the call from DAQFactory using the Dial() function or set the modem up to answer an incoming call (or both).
Dialing out:
To dial out, use the Dial() function: TAPI.Dial("555-1212") This function will return immediately and the dialing will occur asynchronously. You can just put a delay statement after the Dial() to give DAQFactory time to establish the connection: TAPI.Dial("555-1212") delay(30) TAPI.Speak("Alarm on channel 3") TAPI.Drop() However, this method is both inefficient and doesn't handle a busy or no answer condition. Instead you should use the TAPIConnect event. When a connection is established, DAQFactory will try and run a sequence called TAPIConnect in the local connection. It is here that you can put the code you wish to perform when someone actually answers your call. In addition to TAPIConnect, there is TAPIBusy which indicates that a busy signal was detected.
264
wav file stored to disk. Use the PlayFile() function for this: TAPI.PlayFile("c:\windows\media\Chimes.wav") Like most everything in TAPI, the file is played asynchronously, so the function will return immediately. When the playback is complete, DAQFactory will attempt to start a sequence named TAPIPlaybackComplete. You can use this sequence to trigger the next TAPI function on the connection. Of course, since you probably know the playback length, you could just delay: TAPI.PlayFile("c:\windows\media\Chimes.wav") delay(2) TAPI.Drop()
Text to Speech:
One of the most useful parts of TAPI, when combined with SAPI is the ability to do text to speech, or speech synthesis. This allows you to read strings over the phone line that are generated dynamically. So, when an alarm occurs, you could announce the alarm and the current channel value. This is all done with the Speak() function: TAPI.Speak("Alarm, temperature overtemp at " + DoubleToStr(TempChannel[0]) + " degrees") Again, the Speak function runs asynchronously, so DAQFactory will attempt to start a sequence named TAPISpeakComplete when it is done. Microsoft SAPI supports a wide variety of XML commands that can be embedded in your string to control the voice. These are described on the Microsoft website, currently at http://msdn.microsoft.com/library/default.asp?url=/ library/en-us/SAPI51sr/Whitepapers/WP_XML_TTS_Tutorial.asp. If you can't find it there, search for "XML TTS Tutorial". Here is a summary of the common commands. Note that since double quotes (") are used in the XML, you will have to use single quotes (') to specify your string: Volume: <volume level = "80"> The specified value is a percentage of the max voice volume. Speed: <rate speed="5"> The specified value is relative to the default rate of the voice, with negative numbers being slower. Pitch: <pitch middle = "5"> The specified value is relative to the default picth of the voice, with negative numbers being lower pitch. Emphasis: <emph> </emph> The text between the two tags is spoken with emphasis. What this does varies with the voice. Spell: <spell> </spell> The text between the two tags is spelled out rather than pronounced. Silence: <silence msec = "500"> For example: TAPI.Speak('<volume level = "80"><rate speed = "-3"><emph>Alarm</emph> temperature overtemp on <spell>TR392</spell>') A pause with the length specified in milliseconds is generated.
Tone recognition:
DAQFactory can recognize tones generated on the line and perform actions based on these tones. This could be used to remotely acknowledge an alarm, or even provide remote control. Tones are generated by the remote phone by pressing the appropriate key on the phone. When a tone is detected, DAQFactory will attempt to start a sequence called TAPIDTMF. It will pass the parameter "Key" to this event which will contain the character of the tone detected. So, if you wanted to ack your alarms if the user pressed 5, you would put this in the TAPIDTMF sequence: if (Key == "5") Alarm.AckAllAlarms() endif This sequence is called with each tone press, so to detect a series of tones, you will need to use a global or static
12 Networking / Connectivity
265
Speech recognition:
DAQFactory with the help of SAPI can also detect spoken words on the phone line. This could also be used to acknowledge alarms, or provide voice remote control. To use this feature, you will first need to tell DAQFactory what words it should look for. This should be provided as an array of strings using the SetVoiceCommands() function: TAPI.SetVoiceCommands({"Yes","No","Ack"}) Once this function is called, if DAQFactory detects any of the words in the list, it will attempt to run a sequence called TAPISpeechRecognized. It will pass the string of the command recognized in the "Command" private variable. So, like DTMF, you could put the following code to ack your alarms in the TAPISpeechRecognized sequence: if (Command == "Ack") Alarm.AckAllAlarms() endif
Caller ID:
If you have Caller ID service and the incoming call can be identified, DAQFactory will attempt to start a sequence called TAPICallerID passing the detected phone number in "Number". So, if you only wanted to accept calls from 303-555-1212, you could put in the TAPICallerID sequence: if (Number != "3035551212") TAPI.Drop() endif You should probably verify the exact format your Caller ID service provides its phone numbers. In this case, the numbers are stripped of punctuation and always include the area code.
266
the objects of the Local connection. When you establish the connection with a remote copy of DAQFactory, the channels, sequences and other objects are download to your computer. You do not need to recreate the channel list of the remote computer and can very quickly start displaying data. In order to use this feature, the DAQFactory instance you are connecting too must have Broadcasting enabled. This is disabled by default. You can enable it through File-Document Settings from the main menu. We strongly recommend implementing a password for both the slim and full streams, also from this menu. Data between DAQFactory instances is encrypted and the password is used for part of the encryption key. If it is not included, then a default encryption key is used, which is the same across all DAQFactory installations that do not have passwords set.
Connection Name: Enter in a name for your connection. Like all names in DAQFactory, the name must start
with a letter and only contain letters, numbers or the underscore. Make sure you don't use a connection or other object name that you have used before.
Address: Enter in the IP address of the computer that you would like to connect to. You can also enter in a URL
(i.e. mycomputer.mydomain.com), Windows compatible computer name (if on your LAN: i.e. mycomputer) or leave it blank and the connection will be a local connection (when you have another copy of DAQFactory running in Acquire mode locally).
Password: If the remote DAQFactory has passwords assigned to it (through File-Document Settings from the main
menu), you will need to provide the correct password or the connection will not establish.
Full Stream: There are two data streams that are sent out of DAQFactory, the full data stream and the slim
data stream. The full data stream outputs all the data, and allows you to control outputs. A slim data stream will only output data for channels that have the Broadcast field checked (see The Channel Table). In this mode this is all you will see. You cannot set any outputs. This setting is designed for when you have other people connecting to your system and you do not want them to accidentally change any of your process parameters. Once you are finished, press the OK button and the Connection will be created. Please note, though, that these parameters cannot be changed once the Connection is created. If you need to change any of them, you will need to delete the connection and create a new one. To check to see if your new connection was successful, click on the name of the new connection in the Workspace under CONNECTIONS: This will bring up the connection view. Below all the parameters and buttons is displayed the connection status. This will display either Connected or NOT Connected. If the connection is established, then some statistics are also displayed below the Connected label. Once a new connection is created and the connection established, DAQFactory will download its channels and other objects from the remote site. You can then use the Channels as you would on a local connection, displaying their values, or setting outputs. You can also view sequences and other objects in the workspace, but you cannot make any edits over the connection. The same goes for the channels. Sequences and other objects only appear under Full Stream. If for some reason you get disconnected from a remote copy of DAQFactory, the icon next to the connection will have a red line through it. The channels and other objects are still maintained in memory, along with the history for all the channels, so you can still work with the data. Of course no new data will arrive until the connection is reestablished. While the connection is lost, you cannot change any objects, nor can you set outputs or start / stop sequences or other objects. Since DAQFactory can have many different connections, and it is easily possible that two connections could have some channel or other objects with the same name, you will need to specify which connection to use when specifying channels in any expression To do this, simply put the connection name in front of the channel name with a period in between: ConnectionName.ChannelName
12 Networking / Connectivity
267
Typically, most of your data will come from one connection. Because of this, and to keep the expressions easier to read, you can mark one connection as the default connection. When referencing a channel or other object on the default connection you do not need to specify the connection in front of the object name. You can change the default connection at will by opening up the connection view for the desired new default connection and selecting Default? Just be careful, all references to objects in expressions without a specified connection will now refer to different data. This can actually be a benefit if used correctly, but can really throw you if not. The connection view has an additional parameter called Max History Length. Since memory on one machine may be less then another and history is determined by the master machine, you can set a max history length to limit the history length of any channel on the connection to the given value. There are several functions to allow you to programmatically manipulate connections:
System.Connection.Reset(Name): Resets the given connection. Closes the connection then attempts to
reconnect. This does the same thing as clicking the Reset Connection button in the connection view.
System.Connection.Delete(Name): deletes the named connection if it exists. You cant delete the Local
or V connection. If you want to create a runtime that connects to a computer with a varying IP address, call Delete followed by Add with the new IP address and same connection name.
System.Connection.Default(Name): sets the default connection to the given Name. For example:
System.Connection.Default("Local")
268
high speed Stream data nor Spectral data. The server broadcasts at a maximum update rate of 10hz. To your DDE client, the DAQFactory DDE server is called appropriately enough DAQFactory. There are two topics on the server, Data and Time. The Data topic has the data point values; the Time topic has the time of data point in seconds since 1970. Within each topic there will be an item for each channel that has received data. The items available in the Data topic are identical to the ones in the Time topic. Excel makes an easy DDE client. To connect to the DAQFactory DDE server from Excel, you simply enter in the cell you would like the value: =ServerName|Topic!Item So, if we had a channel called MyChannel: =DAQFactory|Data!MyChannel or =DAQFactory|Time!MyChannel You can also combine this into a formula: =(DAQFactory|Time!MyChannel) / 86400 + DATEVALUE("1/1/70") The above formula, for example, converts the time from seconds since 1970 to days since 1900 which is how Excel stores times. You could then set the formatting of the cell to date/time and Excel would display it in a more human readable form. Just make sure you put parenthesis around the DDE reference to keep things clear. Examples Excel spreadsheets filling cells with data are provided in the Samples subdirectory. These show macros for filling cells down with the same value for creating graphs in real-time in Excel.
13 Analysis
XIII
270
13 Analysis
13.1 Analysis overview
DAQFactory provides a significant amount of data processing and analysis tools to complete your data acquisition tasks and convert your data into something useful. Since DAQFactory integrates the data analysis with the data acquisition and data display, you can perform your data analysis on your data as you are taking it.
Capturing Channels:
If you just want to save the history of a single channel, you can capture it to a virtual channel. Use this when something interesting occurs and you want to take a further look without worrying about running out of history length. To capture a channel, simply click on the channel name in the workspace to display the channel view. Click on the button labeled Capture at the top of the view. Next enter in a virtual channel name to capture the history to and press OK. A new static virtual channel with the history of the original channel will be created. The original channel will continue to take data, unaffected by the capture.
Capturing Graphs:
Very often while graphing live data, you will see something interesting and want to spend a little time investigating it. To avoid losing the interesting plot as new data comes in you can always freeze the graph, but eventually the history length of the traces' channels will run out and you will be left with an empty graph. By capturing a graph you can spend as long as you want working with the graph. When you capture a graph, each expression that makes up the traces of the graph are evaluated and stored in virtual channels. A new graph can then be created plotting the virtual channels instead of the real channels and expressions. To capture a graph, simply right click on the desired graph and select Capture from the graph's popup. A capture dialog box will appear which allows you to select which traces to capture and assign virtual channel names to the traces. 2011 AzeoTech, Inc.
13 Analysis
271
Create Graph: If checked, a new graph is created on the scratch page. All the parameters of the new graph
will be identical to the original graph, except the expressions for the traces will be replaced with the virtual channel names the results of the original trace expressions were captured to.
Trace Table: This table will display all the traces and allows you to select which traces get captured and assign
virtual channel names to the results of the capture.
Trace: The Y Expression for the trace. Capture: If checked, then the trace will be captured to a virtual channel. New Virtual Channel Name: Enter the desired virtual channel name to use for this trace. The default is
the trace expression converted to a valid channel name (by converting all invalid values to an underscore).
Select All / Clear All: Either selects or clears the Capture? column.
Please note that error bar, scaling, and annotation Expressions are not captured, though they are copied to the new graph if the Create Graph option is selected.
Main Tab: Function: Select the desired function to fit from the list. Be aware that some functions will not work with
negative X values.
Order: If you selected a polynomial fit, enter the desired order of the polynomial you would like to fit. Y Expression / X Expression: The curve fit routine requires both X and Y data values to fit to. These
Expressions can be identical to the Expressions used to create a trace of your data in a graph. Entering in Time, or leaving the X Expression blank is interpreted the same way it is in generating graphs.
Coefficients: Enter your desired V channel name to store the coefficients. The resulting V channel will be an
array with enough elements to hold all the coefficients of your chosen function. The coefficients are stored in order from left to right as you read the function.
Fitted Curve: Enter a V channel name to store a set of Y values along the fitted curve for the X values of the X
Expression.
Residuals: Enter a V channel name to store the residuals (the difference between the fitted curve and the actual
Y data).
Goodness of Fit: Enter a V channel name to store the Goodness of Fit or Chi-squared value. This is a single
number.
Figure of Merit: Two different methods of determining how good the current coefficients are for the fitted
13 Analysis13.3 Capturing Channels and Graphs
272
Method: Determines the method to move across the goodness of fit space. Both is the best: Downhill simplex is
used first, then the method is switched to Levenberg-Marquardt once the fit gets close.
Local Min Breakout? If you think that the curve fitting routine is finding a local minimum in fit space instead
of the real minimum you can either try and change the initial values or check this parameter. When checked, a special algorithm is used to try and break out of any local minimums. While effective, this method requires a bit more processor time to complete the fit. If curve fitting was initiated from the graph popup, you can select Create Graph to create a new graph on the scratch page with the results of the curve fit. You can also select Add to Graph to add the result of the curve fit to the current graph.
Coefficients Tab: Weights: Enter an expression that evaluates to an array of weight values corresponding to the result of the Y
Expression. The resulting array should be the same size as the result of the Y expression array. If no weight expression is given, all values will be given an equal weighting of 1.
Coefficient table: This table allows you to specify starting values and other parameters relating to your
coefficients. Setting starting values will make your curve fit faster and less likely to end up in a local minimum. Here is a list of the columns and there meanings:
Coefficient: A read only column displaying the corresponding coefficient for the row. The formula is displayed
above the table for your reference.
Initial Value: The starting values to be used for the curve fit. The default is 1 for all parameters. Make sure
you don't specify an illegal value, such as a negative coefficient inside of a log function.
Hold: If checked, then this coefficient will be held at its initial value and not changed during the curve fit. Lower / Upper Bound: Use these two columns to constrain the possible values for a coefficient. If left
empty then there are no constraints.
1st Expression / 2nd Expression: Enter the two expressions to perform the correlation or convolution
function on.
Type: Determines whether an FFT will be performed to aid in the function. Typically this is not necessary. Output Channel: Enter a V channel where the results will be stored. Create Graph: If checked, a new graph will be created on the scratch page with the results displayed.
Correlations typically return 1 dimensional values (the correlation coefficient) and therefore cannot be graphed.
13.7 Histogram
Creates a histogram out from an expression. Bins can come from an expression or be manually generated. This function outputs both X and Y values.
13 Analysis
273
Bins Expression: Enter an expression that evaluates to a sorted array of bin end points. Make sure the
resulting array is sorted. Typically this is used for variable size bins and you will enter the bins expression as a constant array (i.e. {1,4,7,14,20}) or from the results of a previous histogram.
Bins Manual: Generates the bin end points from three parameters, the starting point, the ending point and the
size of each bin. The bins are of uniform size.
Output Histogram: Enter a V channel name to store the results of the histogram. Output Bins: Enter a V channel name to store the bins. A plot of the histogram channel vs. the bins channel
yields the histogram.
Create Graph: If checked, a graph displaying the histogram channel vs the bins channel will be displayed on
the scratch page.
13.8 Interpolation
Use this tool to take a set of X-Y values and interpolate them to a different set of X values.
X / Y Expression: Enter an expression for both the X and Y values. This works just like a graph. You can
enter Time or leave the X Expression blank to use the time or point number associated with the Y values.
Type: Determines which function should be used to perform the interpolation. Interpolate to (X): Enter an expression that results in X values that the X-Y values will be interpolated to. Interpolated Y: Enter a V channel name to store the results of the interpolation. X Values: Enter a V channel name to store the result of the Interpolate To expression. Create Graph: If checked, creates a new graph on the scratch page with the interpolated values displayed.
13.9 Percentile
Creates a percentile graph from the given expression. Like a histogram, this function outputs both X and Y values.
Expression: Enter an expression to perform the percentile calculation on. Values: Enter a V channel to store the Y values of the result of the percentile calculation. Percentile: Enter a V channel to store the X values of the result. A plot of Values vs. Percentile yields the
percentile graph.
Create Graph: Creates a new graph on the scratch value of values channel vs percentile channel.
13.10 FFT
Performs a fast-fourier transform of the given expression.
Expression: Enter an expression to perform the FFT on. FFT Type: Determines how the resulting imaginary array is converted into real numbers.
13 Analysis13.7 Histogram
274
Windowing: Determines which windowing function will be applied to the result of the expression before
performing the FFT.
Output Channel: Enter a V channel name where the results of the FFT will be stored. Create Graph: If checked, a graph will be created on the scratch page displaying the results of the FFT.
14 Other Features
XIV
276
14 Other Features
14.1 Startup Flags
In addition to being able to specify the file to open in the command line when starting DAQFactory, you can use two predefined flags to force DAQFactory into runtime and/or full screen mode. These are -R and -F respectively. You can create your own flags as well. To retrieve your flags in script, call system.GetFlags():
System.GetFlags(): returns an array of strings containing all the flags entered in the command line, with the
exception of a document name, the -R and the -F flags, if specified. So, if you did: DAQFactory.exe MyDocument -F -A -DoSomething to start DAQFactory, and then called System.GetFlags(), you'd get: {"A","DoSomething"}
14.2 Preferences
There are several adjustments that can be made to the DAQFactory environment. These are all available from FilePreferences... from the main menu. These preferences are saved in the registry and apply to DAQFactory as a whole, independent of which document may be loaded. For the colors, you will need to restart DAQFactory for the changes to take effect.
Sequence Loop Check: Depreciated. To help you avoid hanging your computer with an infinite loop,
DAQFactory can do a sequence loop check. The loop check, when active, stops a sequence that executes a preset number of lines in one second. By default, this is 100 lines in one second. When more than 100 lines are executed in a second, the sequence will stop and an alert will display. As you start writing more advanced sequences, you may find that the loop check interferes with your sequences. You can either disable the loop check completely, or specify a larger number of lines. The sequence loop check does not exist in the runtime version of DAQFactory.
Table Font and Font Size: On some systems, the default font for DAQFactory's tables does not appear
correctly. If this occurs on your system, you can select a different font here to make the tables appear properly. This also affects the watch. You must restart for the changes to take effect.
Flash Window on Alert? If checked, the DAQFactory window will flash whenever an alert arrives. If not,
only the alert area of the status bar will flash.
Show all Alerts in Alert box only: This is identical to the option presented when an alert is displayed and
eliminates any alert popups.
Sequence Editor Font and Size: This setting allows you to change the sequence editor font and size. This
is required for some languages to ensure that the editor font supports characters in your language. We strongly recommend using a mono-spaced font. This also affects the command / alert window. You must restart for the changes to take effect.
Expression / Sequence editor colors: This gives you the ability to change the colors used to highlight
certain types of entries in expression boxes and the sequence/event editors. It has no effect on the execution of your documents, just how the editors look. You must restart for the changes to take effect.
Guru Style: This is a special editor color settings that our developers prefer. Perhaps we are just showing our
age, but we prefer white text with a black background, with other colors for comments, strings, etc. This mode also does not display sequence line numbers since these are displayed in the status bar as well. If you want to be like the DAQFactory Gurus or you just like text on a black background like we do, then try Guru Style. You must restart for the changes to take effect.
14 Other Features
277
Default: this is the default background color before any syntax coloring is applied. This is normally white, and is
changed by Syntax Coloring if enabled for expression edit boxes.
Syntax Coloring: Syntax coloring displays the background of an expression edit box in a different color if the
entered expression results in a valid value. A different color is displayed for a numeric result, string result, or invalid result. Syntax coloring actually evaluates the expression. When working with large histories, spectral or image data this can sometimes result in slow response from DAQFactory as it does this. To avoid this, simply disable the syntax coloring. Sometimes syntax coloring will display invalid even when there are no problems. For example, if you are entering an expression that includes a channel or variable that hasn't been initialized, the syntax coloring will show invalid, but once the channel or variable is initialized, the expression will be perfectly valid.
14.3 Alerts
When an error occurs in DAQFactory, an alert is generated. Alerts appear in the docking window at the bottom of the screen labelled Command / Alert. This window maintains a list of alerts along with the command line. Alerts are programmatically available with history like a channel for use in sequences or expressions. strAlert[0] will retrieve the most recent alert message. "strAlert" has a 100 entry history. Note that even though your commands appear in the command/alert window, only alert messages are saved in this history. Alerts are not automatically logged. You must specify them in a logging set by hitting Manual and entering Alert. Alerts are strings so cant be used in binary mode logging sets. Note: to avoid an overflow of alerts, only one alert of a particular type is displayed in any given second.
Alert Preferences:
There are two preferences relating to alerts. These are available from the preferences window by select File Preferences from the main menu. Flash Window on Alert? If checked, the DAQFactory window will flash whenever an alert arrives. If not, only the alert area of the status bar will flash. Show all Alerts in Alert box only: This is identical to the option presented when an alert is displayed and eliminates any alert popups.
Notes are not automatically logged. You must specify them in a logging set by hitting Manual and entering Note. Notes are strings so cant be used in binary mode logging sets. You can programmatically display the notes dialog by calling System.NoteDialog(). This function must be called from the main application thread, so only really works with the Quick Sequence action of many components.
278
14.5 Customizing
You can customize the menus, toolbars, and keyboard accelerators in DAQFactory Control to fit the way you work. To view a list of the current keyboard accelerators, select Help - Keyboard Shortcuts... from the main menu. A dialog box will appear listing all the shortcuts. Make sure and select your desired category, or All Commands to display all the shortcuts. You can use the print or copy icon at the top left corner of the box to print a list of the shortcuts, or copy the list to the clipboard. To edit the shortcuts and other features of Control, select Tools - Customize... from the main menu. The customize dialog box that appears has 5 sheets. Here is a quick description on how to use each sheet. We suggest you experiment to achieve the results that work for you.
Commands: Use to add / remove features from your toolbars or menus. Select from the categories on the left,
then click and drag a command from the list on the right and drop it in a toolbar or menu on the screen. You can also edit the toolbars and menus displayed by clicking and dragging any toolbar button to a new location, or drag it to the main part of the screen to remove it from the toolbar.
Toolbars: Allows you to select which toolbars are displayed (you can also use the View menu from the main
menu). You can also create new toolbars here too. If you completely mess up your toolbars, you can press the Reset or Reset All buttons to restore the toolbar or toolbars to their default settings.
Keyboard: Use to assign keyboard shortcuts to DAQFactory commands. Select the Category and Command
from the drop down and list to the left of the box. To assign a new shortcut, click in the Press New Shortcut Key box, then press the desired key combination. The keys you pressed will appear in the box. Press the Assign button to assign it to the selected command. To remove a shortcut, select the key combination in the Current Keys list and press the Remove button. Press Reset All to restore all the shortcuts to their default values.
Menu: Use this sheet to display the popup menus on the screen. Once displayed, you can edit them by going back
to the Commands sheet and using the functions available there. You can also control menu animations and shadowing from this sheet.
Single Installation:
For this, you will only need the development license. Put the development license on the computer that the end user will be using along with your application. Go to File - Document Settings... and put a password on your document
14 Other Features
279
to prevent the end user from switching to development mode. This will also cause DAQFactory to load the document in runtime mode. Finally, create a shortcut to DAQFactory.exe and add your document name in the target. To do this, right click on the shortcut and select properties. Then in the section under Target, add a space and your document name after DAQFactory.exe:
Now, when DAQFactory loads, it will run your specified document in runtime mode. When you wish to make modifications to the document, you can click on the system menu (the DAQFactory icon at the top left corner of the window) and select "Switch to Development". You will be prompted for the password before switching. Then you can modify your document at will, making sure to save you changes, and then select File - Switch to Runtime mode to revert back. To force a development license into runtime mode at startup, use the -R startup flag as described in the section on startup flags.
280
Full Screen: This will put the runtime in full screen mode. You'll have to hit Alt-Space to open the menu up to
switch out of full screen mode. Use Document Settings under File when creating your document to set the document in Full Screen mode on load. The F4 key can also be used to switch in and out of full screen mode.
On Screen Keyboard: This will display the on screen keyboard for touch screen applications. Switch to Acquire Mode: Runtime acquire mode is designed for applications where two computers are used,
one for acquiring data and one for displaying, and you want to avoid purchasing two full DAQFactory licenses. The rest of the options are for licensing DAQFactory and are discussed in the section on licensing. Here are a few pointers and extra features for runtimes: When designed runtime documents, remember that DAQFactory features accessed through menus are not accessible. Examples include changing pages (if running on a touch-screen), printing pages, and exiting the program. Use component actions for these. One exception is graph scaling and zooming. A user of DAQFactory Runtime can still right click on a graph and perform the zooming functions. You can set the size of a runtime document's window by selecting File - Document Settings... from the main menu. This information gets saved with the document. Note that this is the size of the entire window including the title bar. To have DAQFactory automatically start in Runtime mode, you must have a document editing password on your document. Runtime documents ignore the Sequence Loop Check setting. Make sure and install the necessary device drivers into the runtime directory when installing the runtime. Note: Documents created with DAQFactory Express and trial versions of DAQFactory cannot be used with DAQFactory Runtime.
14 Other Features
281
two copies of DAQFactory on the same machine you will need to select Disable Broadcast on the second, non-Acquire mode copy, to allow the Acquire mode copy to send data. If you want a document to automatically switch to Acquire mode when loaded, you can select Load in Acquire mode. Both this option and Disable Broadcast are under File-Document Settings from the main menu. Note: if Acquire mode needs all your processor speed for data acquisition, no other programs will respond. Therefore, if you are going to experiment with fast time intervals, make sure you save often, and be prepared to reset your computer! If you create an interval that is too quick, you may need to open the document in safe mode and adjust before putting the system in Acquire mode. Note: not all devices benefit from Acquire mode. For example, the LabJack U12 uses Windows functions that don't allow for the priority boost Acquire mode offers and therefore does not benefit from this mode.
15 Extending DAQFactory
XV
15 Extending DAQFactory
283
15 Extending DAQFactory
15.1 Calling an External DLL
15.1.1 External DLL Overview
DAQFactory has the ability to call functions from external DLLs. These DLLs could be libraries provided by a device manufacturer, or simply a DLL with some C functions you created. Either way, DAQFactory can load the DLL and present the function as any other function in DAQFactory. Note: calling of external DLLs, while not terribly difficult, is a bit of an advanced topic. Because the DLLs are loaded dynamically, there is no type checking which can result in a DAQFactory crash if you incorrectly specify the function prototypes. Because of this, it is strongly recommended that you save often to avoid losing any work, both in DAQFactory and your other open applications as an improper call could crash your computer as well. Of course once you correctly specify the prototype you should not have any problems.
Tip: The tool-tip displayed when you type in the function name in a sequence. If not specified, the prototype is displayed. Here's an example of loading the ListAll function from the LabJackUD DLL: extern("labjackud.dll","long ListAll(long, long, long[1], long[128],long[128],double [128])","LJListAll","stdcall") And calling the new function from within DAQFactory: global numfound global sn global id global address global err err = LJListAll(9,1,@numfound,@sn,@id,@address) Note that the DAQFactory function name does not have to be the same as the DLL function name. This example is explained in detail in the next sections. Note: Do not use the extern function to load .lib files. .lib files are used by linkers to identify entry points and do
284
15 Extending DAQFactory
285
Note: If you call extern with the same DLL and the same prototype function name but with different arguments, the old prototype is removed from the system and replaced by your new prototype.
286
I/O Types:
Each I/O type that you create will have a sequence script associated with it. This script will take the device number, channel number and other information and return a value (for inputs) or set a value (for outputs). In the User Device Configuration window you can add new I/O Types to your device by clicking on the Add I/O type button at the bottom. A new window will appear asking about your I/O type. You'll first need to specify the I/O type name. The I/O Type is one of the few places where you can use spaces and other special characters in the name. You'll also need to provide a unique number for your I/O Type. Internally, I/O types are tracked by number. It doesn't matter what this number is, as long as it is a positive integer less than 2^32. Finally you'll need to specify whether the I/O type is an input or output, and whether the data will be numeric or a string. Once you've added a new I/O type it will appear in the list along the left. If you click on the I/O type, the script for this type will appear to the right. Initially, of course, it will be blank. Here you can put in whatever sequence code you need to read or write your values. Remember, though, that this code executes often, so long loops or delays are not recommended. The following private variables are available to you: DeviceNumber - the device number of the channel Channel - the channel number of the channel Specifier - the quick note / opc specifier for the channel SetToValue - the value to set to (output I/O types) strSetToValue - same as above, but the string version OriginalValue - the pre-converted value to set to. Return this for output I/O types. strOriginalValue - same as above, but the string version ChannelName - the name of the channel For input I/O types, you'll want to return the value read at the end of your script. If you don't have a value to return, for example in the case of an error, just return nothing: "return". For output I/O types you will typically want to return OriginalValue to confirm that the output was set, or again, nothing if the value could not be set.
Functions:
Device functions are typically called from sequences. To create a new function, click on the Add Function button at the bottom of the window. You will then be prompted for a function name, which like all other names in DAQFactory, must start with a letter, and contain only letters, numbers or the underscore. Like I/O types, a function is simply sequence code. The arguments passed to the function are just like a sequence used as a function and named arg0, arg1, etc. for each subsequent argument, and prefixed with 'str', i.e. strarg0, when a string is passed. You can optionally return a value as well. There are two types of functions, Public and Private, which is selected at the top right above the code. A public function is visible from anywhere in DAQFactory and typically accessed by Device.MyFunction() notation. A private function is actually available from anywhere, but does not appear in any drop downs when entering code, so is not really visible. Private functions are typically used solely by other functions or I/O types of this device.
OnLoad / OnUnload:
15 Extending DAQFactory
287
In addition to the I/O types that you add, there are two events that exist with every user device and will appear in the I/O type list from the beginning. On Load is called once before any of your I/O type code and allows you to put initialization code. This is a great place to put extern() statements and other initialization. On Unload is called when you quit DAQFactory or when you start a new document or open an existing document. Use this event for any shutdown code. Note that for every On Load called, On Unload will be called once as well. To edit these events, simply click on them in the I/O type list. Note: you cannot remove an I/O type or function from within DAQFactory. To do this, you will need to quit DAQFactory, open the .dds file you specified and remove the I/O type or function and associated code from there.
XVI
289
Serial Configuration:
Connection Name: a valid DAQFactory name for your port. This can be as simple as COM1 or whatever you prefer. Serial Port #: the comm port number. This should be a valid comm port on your computer. For example "1" for COM1. Make sure another program is not using the port. To create a placeholder port, use serial port # 0. This will create the port so you can assign it to a device, but will not initialize the port. Then when you are ready, you can change the port # and parameters from a sequence to start using it. Baud: the baud rate for communications on the comm port. This and the next three items are the standard serial port parameters. Check the documentation for the device you are connecting to for the proper settings. If these 16 Serial and Ethernet Communications16.1 DAQFactory Communications Overview
290
parameters are incorrect you will either get no communications or garbled communications. The improper setting of these parameters is the most common difficulty with serial communications. Byte Size: the number of bits per byte used in communications. Parity: the type of parity bit used in communications. Stop Bits: the number of stop bits used in communications. Timeout: the number of milliseconds to wait for a read / write request to complete. This will depend on the response time of your device. We recommend keeping this between 20 and 2000 milliseconds. Longer timeouts are appropriate when working with slow devices or low baud rates, but will result in a latency in a comm failure condition. Note: if using the Timing parameter of a channel or the wait() function in the polling loop of your serial communications, make sure the timeout is set smaller than the loop time or a backlog of requests will occur in a comm failure condition. For this reason we typically recommend using the delay() function over wait() in serial polling loops. With channel Timing, you will eventually get a Timing Lag error, which is not serious, but an indicator that the things are running slower than you'd hoped. Flow Control Type: determines the type of flow control used for communications. Flow control is the use of extra serial lines or codes to allow the device and the PC to control the speed of communications. Flow control has become less and less common as the speed of external devices has improved. Check the documentation for your device for the proper setting. Hardware uses the standard hardware flow control methods. None does not use any flow control. If only three wires of your serial device are used, then this is the correct setting unless your device uses Xon/Xoff. The three wires would then be Tx, Rx, and ground. Manual uses the settings of the other 5 parameters listed next. Flow Control Parameters: for the proper setting of these parameters, please review the documentation of your remote device. In general these settings are not required. They are only used when Type is set to Manual.
Ethernet Configuration:
Connection Name: a valid DAQFactory name for your port. IP Address: (applies to Ethernet Clients only) the IP address of the remote device. Depending on your network setup, you may be able to use an URL as well. To create a placeholder port, set this to a blank string. This will create the port so you can assign it to a device, but will not initialize the connection. Then when you are ready, you can change the IP address and parameters from a sequence to start using it. Port: the IP port to connect to. For example, you would use 80 to connect to a web server. For the Ethernet Server, this is the port to listen on for new connections. Note that DAQFactory only supports one connection per port for the server. Timeout: the number of milliseconds to wait for a read / write request to complete. This will depend on the response time of your device. We recommend keeping this between 20 and 2000 milliseconds. Longer timeouts are appropriate when working with slow devices or modem Ethernet, but will result in a latency in a comm failure condition. Please see the note above concerning polling loops and timeout. Note: In most cases you will use Ethernet Client and not Ethernet Server, and typically the TCP version as only a few devices (such as SixNet) use UDP. Ethernet Server would typically be used for ModbusTCP slave, or to create your own networking within DAQFactory. Note: Ethernet Server is only available in DAQFactory Standard and higher.
291
include with DAQFactory, you have a couple choices. Your first choice is to contact us and see what would be involved for us to develop a protocol driver for your device. This can often be very simple and affordable. The other choice is to use DAQFactory scripting to write your own protocol driver. For many devices this is actually not a difficult task and is the subject the section, User Comm Protocols.
NULL Protocol:
In addition to the regular DAQFactory protocols and user protocols, there is the NULL Protocol. The null protocol is just that, a nothing protocol. It does nothing. Use this protocol when you wish to use the low level communication functions of the comm port from a sequence or elsewhere in your application. One use for this is when you wish to receive data from a device that does not require polling and simply streams data to you without prompting. Using the OnReceive event of a user protocol is probably better for this type of device, but this serves as an example: In this case you could create a Comm Device with the null protocol, then create a simple sequence to read from the port. For example, to read from a streaming input where each line ends in a carriage return (ASCII 13) you might do: Private string strIn while (1) try strIn = Device.MyComm.ReadUntil(13) ... parse strIn ... catch() // catch any comm errors and ignore endcatch endwhile Note that we don't need a delay() in the loop as long as the timeout on the port is set to at least 20 milliseconds. The loop will run as fast as the data is coming in, but will pause whenever it is waiting for more data.
292
293
Variables:
There are different variables available for serial and ethernet type ports. For this reason, these variables should not be accessed from a user protocol as it will fix the protocol to serial or ethernet. When changing these variables, you must call InitComm() on the port to have them take effect.
294
For Both:
PortName: a string containing the name of the communications port assigned to this device. You can also set this variable to an existing port to change the port on the fly. Just make sure you spell the port exactly how you named it. ProtocolName: a string containing the name of the protocol assigned to this device. You can also set this variable to an existing protocol to change the protocol on the fly. Just make sure you spell the protocol exactly how it appears in the serial/ethernet configuration list. Timeout: the timeout value of the port in milliseconds
295
polling protocol this usually means you put a Write() and a Read() inside the same code segment. To mark the beginning of a code segment, you should use the Lock() function of the device. This function returns 1 if it is safe to execute the subsequent code, or 0 if it is not. The function will return 0 if another thread is using the port and your code can't acquire the lock within the port's current timeout period. You should never proceed if it returns 0 and should probably generate an error message instead: Private strDataIn if (!Device.MyDevice.Lock()) throw("Port in use!") endif Device.MyDevice.Write("GiveMeData"+Chr(13) strDataIn = ReadUntil(13) Device.MyDevice.Unlock() To mark then end of the protected segment, you should use the Unlock() function. This function always succeeds. Its actually relatively straight forward if you follow this format, and not nearly as dangerous as normal Mutexes. There are several points though: 1) If an error occurs, Unlock() never gets called, leaving the port blocked. This can be solved with a try / catch block: Private strDataIn if (!Device.MyDevice.Lock()) throw("Port in use!") return endif try Device.MyDevice.Write("GiveMeData"+Chr(13) strDataIn = ReadUntil(13) Device.MyDevice.Unlock() catch() Device.MyDevice.Unlock() throw() endcatch 2) You could inadvertently stop the sequence midstream and therefore leave the device locked and the port blocked. Fortunately, unlike Mutexes, you can call Unlock() on a device from any sequence and it will release the port. This should be used as a last resort though, and proper try/catch coding is the best solution. 3) The Lock() and Unlock() are port specific, not device specific. This allows you to apply multiple protocols to the same serial port without interference.
296
1) The File Name should end in .ddp instead of .dds. It still must be placed in your DAQFactory installation directory. 2) You should use the low level comm functions to communicate with your device. They are all local to your protocol code. Since you don't know what comm device your protocol might be assigned to, you should not use the Device. CommDevice. notation described in the section on low level comm, but instead simply reference the functions directly. For example: Write("GetSomeData" + Chr(13)) strResult = ReadUntil(13) This will insure that your protocol will work with whichever port it gets assigned to. 3) Since you will probably be using the low level comm functions, you can ignore the parts about extern DLL calls. Instead, you probably should do a Purge() or perhaps an Init() in your OnLoad event, and maybe a Purge() in the OnUnload event. 4) In addition to the OnLoad() and OnUnload() events, there are additional events called OnReceive(strIn) and OnSend(strOut). OnReceive() is called with every character received on the port and OnSend() is called with every string sent out the port. Note the difference, OnReceive() is with every individual character, while OnSend() is with each complete string (i.e. with each Write() call) not each character in the string. OnReceive() passes in the variable strIn that contains the character received, while OnSend() passes in the variable strOut containing the string sent out. Note: You cannot Write() from within the OnSend() event. This will create an infinite loop as Write() will trigger the OnSend() event. If you do so, you are likely to hang the communications and have to restart DAQFactory. You can, however do Read() and ReadUntil() from within the OnReceive, which is often very handy. For example, if you have a device that simply outputs a value every second followed by a carriage return, you might put: if (strIn == chr(13)) // we've received the EOL character private string DataIn = ReadUntil(13) // read what we've accumulated Channel.AddValue(strDevice,0,"Input",0,StrToDouble(DataIn)) endif This routine also shows the use of the AddValue() command that doesn't require a channel name and the strDevice variable of your device. You would want to create an I/O type called "Input", but with no code. The code above will take the value and put it in our device, D# = 0, I/O Type "Input" and channel 0. 5) When you create a new protocol, a standard Poll() function is created for you. This function performs a simple poll and wait for response. Its format is Poll(string out, until) where out is the string to send out the port, and until is the ASCII code that marks the end of the incoming line. This function will generate an error if there is a timeout, otherwise it will return the string received. The script for the code is completely viewable and even editable. The function is a very commonly used function and is provided to make creating new protocols easier. 6) Even though you may be sending your value out as a string using Write() or reading it as a string with Read(), you will probably want your I/O types to be numeric. The deciding factor is how DAQFactory stores the value internally for calculations and not how the communication with the actual device is done. 7) Local variables are specific to the device the protocol is assigned to, not the protocol itself. This means if you use the same user protocol on two different ports and therefore two different comm devices, you will have two sets of local variables. 8) Within a function or I/O type, you can access the device name that the user assigned your protocol two through the strDevice variable. This is most often used with the Channel.AddValue() function as shown above.
297
There are two ways within DAQFactory to communicate with your DF1 device. You can use channels as you would other devices, or you can use device functions. You can use a combination of methods as well. Both methods require you to setup a serial / ethernet device first. This is done with the device configurator which was described just previously. The DF1 protocol uses a slightly different addressing method than most PLCs. Please note: ENQ retry should be disabled on your PLC. It is not implemented by DAQFactory and should not be needed. Addressing: The general format of item names for data from DF1 controllers matches the naming convention used by the programming software. The format is shown below. (The parts of the name shown in square brackets ([ ]) are optional.) X [FILE] : ELEMENT [.FIELD] [/BIT] X: Identifies the file type. The list below summarizes the valid file types and the default file number for each type:
File Type
Default File
*Output
*Input
Status
Binary
Timer
Counter
Control
Integer
**Floating P
* Output and Input file types may be Read Only depending on the SLC-500 model. ** Available only on certain SLC500 models. Check the Processor Manual for the model being used. If the Floating Point file type is not supported, file 8 is reserved and unusable. FILE: File number must be 0-255 decimal. File 0 must be Output, file 1 must be Input, file 2 must be Status and so on for all the default file types. If this number is not specified, the default file number will be used. ELEMENT: Element number within the file. For Input and Output files it must be between 0 and 30 decimal. All other file types, it must be between 0 and 255 decimal. FIELD: Refers to the subelement number. If the file type is Timer, Counter or Control, then the subelement field must be replaced by its corresponding number. In some cases there is no reference needed for a subelement number, and if a subelement is included in the command, it will be ignored.
16 Serial and Ethernet Communications16.9 Predefined Protocols16.9.1 Allen Bradley DF1 protocol
298
BIT: Valid for all file types except Floating Point. Must be 0-15 decimal. When setting discrete outputs in groups, you cannot specify a group that passes a word boundary. In other words, if you have a BIT value of 14, you can only set two bits at a time. It will not roll over to the next word. File Items: OUTPUT FILE ITEMS: O[n]:e.s[/b] "n" represents the file number and is optional. If not specified, it is assumed to be zero. "e" indicates the element number in the file. "s" indicates the sub-element number (0 - 255). "b" specifies the bit (0 - 15 decimal.) "/b" may be omitted if necessary to treat the I/O group as a numeric value.
Examples: O0:0/0 O:2/15 O:3 INPUT FILE ITEMS: I[n]:e.s[/b] "n" represents the file number and is optional. If not specified, it is assumed to be one. "e" indicates the element number in the file. "s" indicates the sub-element number (0 - 255). "b" specifies the bit (0 - 15 decimal.) "/b" may be omitted if necessary to treat the I/O group as a numeric value.
Examples: I1:0/0 I:2/15 I:3 ADDRESSING I/O MODULES: The elements (words) in I/O modules are mapped into a memory table. If the Analog I/O modules are being used, then the point naming will differ from the point naming in the programming software. The Item Name must be computed from the sum total of words used by the previous input or output blocks regardless their relative position in the module rack. The operator can use the programming software Data Monitor to look at the memory map of the I file or O file to verify your address. If the address is unsure, or if the PLC configuration is likely to change, copy the points in question to the N table or B table and access the data from there. LABEL I/O MODULES WITH "WORD COUNTS": The address of any point within the I/O datatable space, in an SLC processor, is the sum of the words occupied by previous modules (to the left in the rack) of the same type. Therefore, to determine the correct address for any particular point in the I/O datatable, one must know the number of words each module will consume. Refer to the list below: N. of Words Module 0 1 1 1 4 4 1 2 1747-L524 SLC 5/02 Module Processor 1746-IA8 8 point 120VAC input module 1746-OA16 16 Point 120VAC output module 1746-IA16 16 point 120VAC input module 1746-NI4 4 point 20mA analog input module 1746-NO4I 4 point 20mA analog output module 1746-0A8 8 point 120VAC input module 1746-IB32 32 point DC input module
NOTE: In the table above, the minimum amount of words which can be consumed by a module is 1 (16 bits). This is due to the memory scheme of all Allen-Bradley processors. STATUS FILE ITEMS:
299
S[n]:e[/b] - "n" represents the file number and is optional. If not specified, it is assumed to be two. - "e" indicates the element number in the file (0 - 255 decimal). - "b" is optional. If specified, it indicates the bit (0 - 15 decimal). NOTE: Refer to the SLC-500 Family Processor Manual (Allen-Bradley Publication) for a complete description of Status file information. Examples: S2:6 (major error fault) S2:13 (math register) S:1/5 (forces enabled) BINARY FILE ITEMS: B[n]:e/b or B[n]/m - "n" represents the file number and is optional. If not specified, it is assumed to be three. If specified, the file number must be between 9 and 255 decimal. - "e" specifies the element (word) number within the Binary file. It must be between 0 and 255 decimal. - "b" specifies the bit number within the word. In the first form (where ":e" is present,) the bit number must be between 0 and 15 decimal. - "m" also represents the bit number. However, in the second form, no word number is specified and the bit number may be between 0 and 4095. Examples: B3/4095 (same bit as B:255/15) B:6/4 (same bit as B/100) B3 TIMER FILE ITEMS: T[n]:e[.f][/b] - "n" represents the file number and is optional. If not specified, it is assumed to be four. If specified, the file number must be between 9 and 255 decimal. - "e" specifies the element number (three words per element) within the Timer file. It must be between 0 and 255 decimal. - "f" identifies one of the valid Timer fields. The valid fields for Timer Files are listed in the table below (use the numeric order as reference). If "f" is omitted, it is assumed to be the word 0. - "b" is optional and is normally not used. All of the fields of a timer can be accessed by specifying the ".f" fields. However, it is possible to use "/b" to single out a bit in the .PRE or .ACC fields (which are words). Order number Timer Fields 0 1 2 3 4 .PRE .ACC .EN .TT .DN
Examples: T4:0.1 (means: .ACC) T4:3.4 (means: .DN) T4:1.0 (means: .PRE) COUNTER FILE ITEMS: C[n]:e[.f][/b] - "n" represents the file number and is optional. If not specified, it is assumed to be five. If specified, the file number must be between 9 and 255 decimal.
16 Serial and Ethernet Communications16.9 Predefined Protocols16.9.1 Allen Bradley DF1 protocol
300
- "e" specifies the element number (three words per element) within the Counter file. It must be between 0 and 255 decimal. - "f" identifies one of the valid Counter fields. The valid fields for the Counter Files are listed in the table below (use the numeric order as reference). If "f" is omitted, it is assumed to be the word 0. - "b" is optional and is normally not used. All of the fields of a counter can be accessed by specifying the ".f" fields. However, it is possible to use "/b" to single out a bit in the .PRE or .ACC fields (which are words). Order number Counter Fields 0 1 2 3 4 5 6 7 .PRE .ACC .CU .CD .DN .OV .UN .UA
Examples: C5:0.1 (means: .ACC) C5:3.5 (means: .OV) C5:1.0 (means: .PRE) CONTROL FILE ITEMS: R[n]:e[.f][/b] - "n" represents the file number and is optional. If not specified, it is assumed to be six. If specified, the file number must be between 9 and 255 decimal. - "e" specifies the element number (three words per element) within the Control file. It must be between 0 and 255 decimal. - "f" identifies one of the valid Control fields. The valid fields for the Control files are listed in the table below (use the numeric order as reference). If "f" is omitted, it is assumed to be the word 0. - "b" is optional and is normally not used. All of the fields of a Control file can be accessed by specifying the ".f" fields. However, it is possible to use "/b" to single out a bit in the .LEN or .POS fields (which are words). Order number Control Fields 0 1 2 3 4 5 6 7 .LEN .POS .EN .DN .ER .UL .IN .FD
Examples: R6:0.0 (means: .LEN) R6:3.2 (means: .EN) R6:1.1 (means: .POS) INTEGER FILE ITEMS: N[n]:e[/b] - "n" represents the file number and is optional. If not specified, it is assumed to be seven. If specified, the file number must be between 9 and 255 decimal. - "e" specifies the element number within the Integer file. It must be between 0 and 255 decimal. - "b" is optional. If specified, it indicates the bit (0 - 15 decimal). Examples: N7:0 N7:0/15
301
N7:3 FLOATING POINT FILE ITEMS: F[n]:e - "n" represents the file number (optional). If not specified, it is assumed to be eight. If specified, the file number must be between 9 and 255 decimal. - "e" specifies the element number within the Floating Point file. It must be between 0 and 255 decimal. Examples: F8:0 F8:2 {If you are using 1747-KE} Note: Remember to configure the 1747-KE using the following settings: - Use the DF1 FULL DUPLEX Protocol - Use the checksum mode (BCC or CRC) as stated in P5 parameter. - Use the baud-rate, parity, stop bits and data bits that are currently used in the driver settings. Note: You should verify these settings by connecting your PC to the 1747-KE CONFIG port using an ASCII terminal (i.e. PROCOMM or XTALK) and then follow the steps described in the 1747-KE User Manual. Note: Be careful to include the 1747-KE node address as the source node if it is other than 0. DF1 Channels: If you are reading a small number of inputs, the channel method of acquiring data from your SLC-500 device is the easier method. It is not the most efficient however, because each tag that is read from your device requires a separate request. After creating a new communications device as described previously, create a new channel, select your device name for the device type, enter the ID of the unit you are trying to communicate with as the device #, select the particular DF1 command from the I/O type, and enter the SLC-500 memory address as the Quick Note / Special / OPC column. The channel # parameter can be anything and is ignored. I/O Types: All of these types will read or output to a single memory location: Read Analog BCC Read Analog CRC Read Binary BCC Read Binary CRC Write Analog BCC Write Analog CRC Write Binary BCC Write Binary CRC DF1 Functions: This device includes functions accessible from sequences for more advanced control over your device. The biggest benefit of using device functions over creating individual channels is that you can read groups of memory locations with a single call which is more efficient. For smaller applications this may not be a problem, but if you need to read large blocks of consecutive tags, you will probably want to consider using device functions. There are two basic formats for the device functions, input and output. Input functions take the ID of the device you wish to communicate with, the starting address, the number of points to read, and whether to use CRC or BCC. Input functions return an array of values corresponding to the data read. Output functions also take the same parameters, but take an array of values to set your memory locations to instead of the number of values. Output functions do not return anything. You will still need to create a new communications device as described previously. For these examples, we'll assume
16 Serial and Ethernet Communications16.9 Predefined Protocols16.9.1 Allen Bradley DF1 protocol
302
you called it MyDevice. Example - reading 8 holding register values: data = Device.MyDevice.ReadAnalog(10,"F8:0",8,0) This will read 8 values from device ID #10 starting memory location F8:0 in BCC mode and store the result in the data memory variable (which was declared previously). Example - using the device function to pull blocks of data into channels: 1. Starting from a blank document, create your communications device using the Device Configurator. 2. Click on CHANNELS: in the workspace to go to the channel table. Click on the Add button to add a new channel row. Give the row the name Input10. You can of course use more appropriate names if you would like. Set the Device Type to MyDevice or whatever you named your communication device. Set the Timing column to 0. This last step is very important otherwise DAQFactory will start to poll the device directly for this channel. With the exception of the channel name, which must be unique, and the Timing, which must be set to 0, you can set the other channel parameters to anything. We still recommend selecting a device type that matches your device. 3. Click on the Duplicate button 7 times to create 7 new channels based off of the one you just created. DAQFactory will automatically give each the name: Input11, Input12, etc. Click Apply to save your changes. 4. Right click on SEQUENCES: in the workspace and select Add Sequence to create a new sequence. Call the new sequence GroupRead and click OK. You will be placed in the sequence view ready to edit your sequence. Here is the code to enter: private data while (1) data = Device.MyDevice.ReadAnalog(10,"F8:0",8,0) Input10.AddValue(Private.data[0][0]) Input11.AddValue(Private.data[0][1]) Input12.AddValue(Private.data[0][2]) Input13.AddValue(Private.data[0][3]) Input14.AddValue(Private.data[0][4]) Input15.AddValue(Private.data[0][5]) Input16.AddValue(Private.data[0][6]) Input17.AddValue(Private.data[0][7]) delay(1) endwhile 5. Click Apply to save your sequence. Now click on the + sign next to SEQUENCES in the workspace to expand the tree, then right click on the GroupRead sequence and select Begin Sequence. 6. Now go to the channel view for any of your register channels and look at the table of the data coming in. (click on the + next to CHANNELS:, then click on the channel name and select the Table tab). The sequence loops once a second and reads 8 addresses in a single call to your device. The 8 Input statements in the middle add the newly read values to the channels you created earlier. For those wondering why the data always has [0] after it, then [x] where x is the tag number: the first dimension of arrays in DAQFactory is always in time. Since all these values were read at once they all have the same time so all are on the same row (first dimension). Besides consistency, this allows you to create 2 dimensional arrays of data from multiple tags very easily. Example - setting 8 outputs: Private outdata = {{1,0,0,1,0,0,0,1}} Device.MyDevice.WriteBinary(32,"N7:0/3",Private.outdata,1) This will set 8 addresses on device ID #32 starting at memory location N7:0/3 in CRC mode. The values will be on, off, off, on, off, off, off, and on and will start at the 3rd bit of N7:0. Note that you cannot set bits across a word boundary in a single call. Functions: ReadAnalog ReadBinary
303
WriteAnalog WriteBinary
At the top you can select which base or expansion unit (if any) to configure. You can also select the type of modules you will be using (5V or 10V). Then for the base and each expansion unit you may have, select the module installed in each position. To make it easy to select from the rather wide variety of modules, the modules are split into categories based on the first few numbers of the model. Select the category, then select the model within that category. When finished, click OK. Once this is configured, any reads or writes to the device can be done in engineering units. For example, temperature will read in degrees Celsius. The I/O types available are pretty straightforward. Average Input, Max Input, and Min Input are provided by the device and not DAQFactory as described in the isoLynx manual. Analog Output Readback allows you to read the analog output setting from the device. There is a corresponding device function for each I/O type which you can use if you need better error handling. 16 Serial and Ethernet Communications16.9 Predefined Protocols16.9.1 Allen Bradley DF1 protocol
304
There are two ways within DAQFactory to communicate with your device. You can use channels as you would other devices, or you can use device functions. You can use a combination of methods as well. Both methods require you to setup a serial / Ethernet device first. This is done with the device configurator which was described just previously. The A/Q protocol uses a slightly different addressing method than most PLCs. The addressing consists of a letter describing the data type followed by the address. For example D123 or T010. Because a channel's channel number only supports numbers, there is a separate I/O type for each of the possible data types. The number after the letters is specified as the channel. So, D123 would be I/O type "Read D" and channel # 123. The D#, or Device Number is the station ID of the device. If you need the NetStation parameter in your network, put this number in the Quick Note / Special column of the channel. Otherwise this defaults to 255. This driver allows you to either create a separate channel for read and write tags for a single address, or you can create a single read tag for each address and simply write to it to make it into a read/write tag. The channels will automatically optimize calls to use the minimal amount of calls required. For best efficiency, you should try and place memory locations consecutively within the PLC, and make sure all channels in a group of consecutive values have the same timing and offset. FX Functions: This device includes functions accessible from sequences for more advanced control over your device. There are three functions used to set configuration information of the driver, and a separate function for each I/O type. The advantage of using these functions over channels is that you can do error handling and have a little finer control over the polling.
SetCPUType(type): use to specify whether you have an A or AnA / AnU PLC. Specify 0 for A (or Q) and 1 for
AnA/AnU.
SetMessageFormat(type): use to specify mode 1 or mode 4 protocol. Simply specify 1 or 4. The default is
mode 1.
SetMessageWait(delay): specifies the message wait time. The default is 0. This is not the timeout, but
instead used in the protocol. There are two basic formats for the rest of the device functions, input and output. Input functions take the station ID, starting address and the number of points to read. You can also optionally specify the NetStation, otherwise it defaults to 255. Input functions return an array of values corresponding to the data read. Output functions also take the same parameters, but take an array of values to set your memory locations to instead of the number of values. Output functions do not return anything. You will still need to create a new communications device as described previously. For these examples, we'll assume you called it MyDevice. Example - reading 8 TN register values starting at TN10: data = Device.MyDevice.ReadTN(1,10,8) This will read 8 values starting memory location TN10 and store the result in the data memory variable (which was declared previously). Example - setting 8 outputs: Private outdata = {{1,0,0,1,0,0,0,1}} Device.MyDevice.WriteTN(1,10,Private.outdata)
305
This will set 8 addresses starting at memory location TN10. The values will be on, off, off, on, off, off, off, and on. All input functions have the parameter list (Station, Starting Address, Num Points, [NetStation]). All outputs have the parameter list (Station, Starting Address, {Data}, [NetStation]).
306
There are two basic formats for the device functions, input and output. Input functions take the starting address and the number of points to read. Input functions return an array of values corresponding to the data read. Output functions also take the same parameters, but take an array of values to set your memory locations to instead of the number of values. Output functions do not return anything. You will still need to create a new communications device as described previously. For these examples, we'll assume you called it MyDevice. Example - reading 8 holding register values: data = Device.MyDevice.ReadUnsignedWord("D10",8) This will read 8 values starting memory location D10 and store the result in the data memory variable (which was declared previously). Example - using the device function to pull blocks of data into channels: 1. Starting from a blank document, create your communications device using the Device Configurator. 2. Click on CHANNELS: in the workspace to go to the channel table. Click on the Add button to add a new channel row. Give the row the name Input10. You can of course use more appropriate names if you would like. Set the Device Type to MyDevice or whatever you named your communication device. Set the Timing column to 0. This last step is very important otherwise DAQFactory will start to poll the device directly for this channel. With the exception of the channel name, which must be unique, and the Timing, which must be set to 0, you can set the other channel parameters to anything. We still recommend selecting a device type that matches your device. 3. Click on the Duplicate button 7 times to create 7 new channels based off of the one you just created. DAQFactory will automatically give each the name: Input11, Input12, etc. Click Apply to save your changes. 4. Right click on SEQUENCES: in the workspace and select Add Sequence to create a new sequence. Call the new sequence GroupRead and click OK. You will be placed in the sequence view ready to edit your sequence. Here is the code to enter: private data while (1) data = Device.MyDevice.ReadUnsignedWord("D0",8) Input10.AddValue(Private.data[0][0]) Input11.AddValue(Private.data[0][1]) Input12.AddValue(Private.data[0][2]) Input13.AddValue(Private.data[0][3]) Input14.AddValue(Private.data[0][4]) Input15.AddValue(Private.data[0][5]) Input16.AddValue(Private.data[0][6]) Input17.AddValue(Private.data[0][7]) delay(1) endwhile 5. Click Apply to save your sequence. Now click on the + sign next to SEQUENCES in the workspace to expand the tree, then right click on the GroupRead sequence and select Begin Sequence. 6. Now go to the channel view for any of your register channels and look at the table of the data coming in. (click on the + next to CHANNELS:, then click on the channel name and select the Table tab). The sequence loops once a second and reads 8 addresses in a single call to your device. The 8 Input statements in the middle add the newly read values to the channels you created earlier. For those wondering why the data always has [0] after it, then [x] where x is the tag number: the first dimension of arrays in DAQFactory is always in time. Since all these values were read at once they all have the same time so all are on the same row (first dimension). Besides consistency, this allows you to create 2 dimensional arrays of data from multiple tags very easily. Example - setting 8 outputs: Private outdata = {{1,0,0,1,0,0,0,1}} Device.MyDevice.WriteBit("D0",Private.outdata) This will set 8 addresses starting at memory location D0. The values will be on, off, off, on, off, off, off, and on. Note that you cannot set bits across a word boundary in a single call.
307
Functions: ReadBit ReadU16 ReadS16 ReadU32 ReadS32 ReadFloat WriteBit WriteU16 WriteS16 WriteU32 WriteS32 WriteFloat
Detail: Unfortunately some manufacturers 0 index their addresses and others use 40,001 type notation. Internally, the Modbus packet itself uses 0 indexing. The Modbus protocol driver will assume you are using 0 indexed addresses until you try and read from an address greater than 30,000, but less than 50,000. Once you do this, it will assume you are using 40,001 type notation and subtract the appropriate value to send the correct request. This will apply to all the devices using the protocol. In general you don't have to worry about this, unless you are only setting coils and output registers and still want to use the 1 indexed, 40,001 type notation. In this case you will either need to read a single holding or input register with an address greater then 30,000 or manually adjust your tag numbers to 0 indexed.
16 Serial and Ethernet Communications16.9 Predefined Protocols16.9.4 Mitsubishi FX direct serial protocol
308
Alas, some devices use 0 index notation, but number their registers up into the 30,000 and 40,000. To force the driver into 0 index mode, read an address greater than 50,000. Then the driver will remain in 0 indexed mode even if you read a 30,000 or 40,000 address. In the I/O type, the number in parenthesis refers to the Modbus command number used. Since even the terminology of Modbus varies some between manufacturers, we have provided this to help keep things clear. This driver allows you to either create a separate channel for read and write tags for a single address, or you can create a single read tag for each address and simply write to it to make it into a read/write tag. Obviously, when writing to a read tag the Modbus command number indicated will be substituted for the appropriate output command number. Also, you can only write to Holding registers and coils and not to input registers. You also cannot write to the U16 data type. Use S16 instead. DAQFactory will automatically combine sequential channels with the same Timing and Offset into a single request to optimize the traffic on your comm port. When doing floating or 32 bit values, it assumes sequential channel numbers are in steps of 2 (40,001, 40,003, etc.). For the "skip 2" I/O types, it assumes sequential channel numbers are in steps of 3. Example - reading a holding register once a second: 1. From a blank document, create a new Communication Device selecting ModbusRTU as the protocol. Read the section on the creating a Comm Device for more information. We'll assume for all these examples that you called your device MyDevice. 2. Click on CHANNELS: in the workspace to go to the channel table. Click Add to add a new channel row. In that new row, enter a channel name such as Register1. Select MyDevice for the device type, then enter the ID of your device under D#. For the I/O type, select Read Holding U16 (3). You may have to expand the column to read it. The U16 means "Unsigned 16 bit integer" and is the same as an unsigned word. (3) means we are using Modbus command 3. Under Chn #, enter the memory location for the register you would like to read. Holding registers are normally numbered from 30000. However the 3 only identifies the address as a holding register and is not required. Therefore if your memory address is 30063 you should enter a channel number of 63. 3. Click Apply to save your changes. Since the channel you just created has a Timing parameter of 1.00, DAQFactory will immediately start polling that holding register once a second. 4. To quickly see the data, click on the + next to CHANNELS: in the workspace to expand the tree. Then click on your new channel name. This will display the channel view for this channel. Click on the Table tab to see the data in tabular form. You can now either add more channels, or go to the page and use page components to display your acquired data. Example - forcing a coil: 1. From a blank document, create a new Communication Device selecting ModbusRTU as the protocol. Read the section on the creating a Comm Device for more information. We'll assume for all these examples that you called your device MyDevice. 2. Click on CHANNELS: in the workspace to go to the channel table. Click Add to add a new channel row. In that new row, enter a channel name such as Register1. Select MyDevice for the device type, then enter the ID of your device under D#. For the I/O type, select Force Coil (5). You may have to expand the column to read it. Under Chn #, enter the memory location for the coil you would like to set. 3. Click Apply to save your changes. To quickly toggle the state of the coil, right click on the channel row and select Toggle. You should see your coil toggling between on and off. You can now either add more channels, or go to the page and use page components to control your output coil. I/O Types: All of the types will read or output to a single memory location. The number in parenthesis is the Modbus command used. Many of the commands are identical and the difference is how the data is treated. Here is a description of the codes used: U16 S16 U32 S32 U32 : unsigned 16 bit word : signed 16 bit word : unsigned 32 bit double-word (long unsigned integer) : signed 32 bit double-word (long integer) R Words : unsigned 32 bit double-word with words reversed 2011 AzeoTech, Inc.
309
S32 R Words : signed 32 bit double-word with words reversed Float : 32 bit floating point value Float R Bytes : 32 bit floating point value with bytes reversed Float R Words : 32 bit floating point value with words reversed Skip 2 : skip 2 bytes before reading the value Modbus Functions: This protocol includes functions accessible from sequences for more advanced control over your device. This is especially useful when you want to optimize the writing of multiple consecutive values to your device as the channels themselves cannot optimize outputs, only inputs. There are two basic formats for the device functions, input and output. Input functions take the ID of the device you wish to communicate with, the starting address, and the number of points to read. Input functions return an array of values corresponding to the data read. Output functions also take the ID and starting address, but then take an array of values to set your memory locations to. Output functions do not return anything. To use these functions you must create a new Communication Device with the ModbusRTU as its protocol. Read the section on the creating a Comm Device for more information. We'll assume for all these examples that you called your device MyDevice. Example - reading 8 holding register values: data = Device.MyDevice.ReadHoldingU16(32,10,8) This will read 8 values from device ID #32 starting memory location 10 and store the result in the data memory variable. Example - using the device function to pull blocks of data into channels. This can also be done by simply setting all your channels to the same Timing / Offset. The driver will automatically optimize the calls to your device. But, as an example, you can also: 1. From a blank document, create a new Communication Device selecting ModbusRTU as the protocol. Read the section on the creating a Comm Device for more information. We'll assume for all these examples that you called your device MyDevice. 2. Click on CHANNELS: in the workspace to go to the channel table. Click on the Add button to add a new channel row. Give the row the name Register10. You can of course use more appropriate names if you would like. Set the Device Type to MyDevice. Set the Timing column to 0. This last step is very important otherwise DAQFactory will start to poll the device directly for this channel. With the exception of the channel name, which must be unique, and the Timing, which must be set to 0, you can set the other channel parameters to anything. We still recommend selecting a device type that matches your device. 3. Click on the Duplicate button 7 times to create 7 new channels based off of the one you just created. DAQFactory will automatically give each the names: Register11, Register12, etc. Click Apply to save your changes. 4. Right click on SEQUENCES: in the workspace and select Add Sequence to create a new sequence. Call the new sequence GroupRead and click OK. You will be placed in the sequence view ready to edit your sequence. Here is the code to enter: private data while (1) data = Device.MyDevice.ReadHoldingU16(32,10,8) Register10.AddValue(Private.data[0][0]) Register11.AddValue(Private.data[0][1]) Register12.AddValue(Private.data[0][2]) Register13.AddValue(Private.data[0][3]) Register14.AddValue(Private.data[0][4]) Register15.AddValue(Private.data[0][5]) Register16.AddValue(Private.data[0][6])` Register17.AddValue(Private.data[0][7]) delay(1) endwhile 5. Click Apply to save your sequence. Now click on the + sign next to SEQUENCES in the workspace to expand the tree, then right click on the GroupRead sequence and select Begin Sequence. 6. Now go to the channel view for any of your register channels and look at the table of the data coming in. (click on the + next to CHANNELS:, then click on the channel name and select the Table tab). The sequence loops once a second and reads 8 registers in a single call to your device. The 8 Register statements in the middle add the newly
310
read values to the channels you created earlier. For those wondering why the data always has [0] after it, then [x] where x is the tag number: the first dimension of arrays in DAQFactory is always in time. Since all these values were read at once they all have the same time so all are on the same row (first dimension). Besides consistency, this allows you to create 2 dimensional arrays of data from multiple tags very easily. Example - setting 8 coils: Private.outdata = {{1,0,0,1,0,0,0,1}} Device.MyDevice.ForceMultipleCoils(32,20,Private.outdata) This will set 8 coils on device ID #32 starting at memory location 20. The values will be on, off, off, on, off, off, off, and on. Functions: The functions available start with either ReadInput, ReadHolding, ReadCoil, ForceCoil or SetRegister and follow the same coding as I/O types described above. Note: Once the data is within DAQFactory, it is treated as a 64 bit floating point value.
17 Devices
XVII
312
17 Devices
17.1 Device Overview
As a data acquisition package, DAQFactory must communicate with many different pieces of hardware. To enable DAQFactory to do so, it uses what are called Devices. These are libraries of code that act as translators between DAQFactory and the particular piece of hardware you would like to use. AzeoTech offers a wide variety of devices to allow you to communicate with an even larger variety of data acquisition and process control hardware and sensors. This chapter provides specific information for each device currently shipped with DAQFactory. Additional and updated devices are made available from our website at www.azeotech.com. We can also provide you with custom or enhanced devices for a modest cost if you would like.
Installing a device:
When DAQFactory ships, it installs a wide selection of devices. However, we are constantly creating new devices and updating old ones. Typically, installing these new devices is simply a matter of pointing the install program to the directory where DAQFactory is installed. Almost all devices are simply made up of a .dll file with the code for the actual device and a .dds text file with some information about the device. Note: Most hardware specific devices require drivers from the manufacturer. The drivers must be installed for the corresponding DAQFactory device drivers to function. If you are getting the C1033 error, it may be because your hardware manufacturer driver is not installed, or because a required DLL from the manufacturer cannot be found. Tip: If you would like to remove a device from the list of possible devices displayed when creating Channels, simply rename (or delete) the .dds file associated with the device(s) you would like to remove to something without a .dds extension. DAQFactory only loads devices with a .dds file associated with them.
17 Devices
313
This window allows you to identify a base address and device # for each Acces I/O board in your system. The base address is the address assigned to your board, usually through DIP switches or jumpers. The device # is an arbitrary number you will use to identify each board. The number simply has to be unique for each Acces I/O board in your system. When you first start, this window will be empty. 3. Click Add Device to add your first Acces board:
4. A new window will appear. Select your Acces I/O board type. Enter in an arbitrary device number, zero is perfectly acceptable. Finally, enter the base address assigned to the board by its DIP switches or jumpers. You will have to check your manual with your board to determine the meaning of the switches or jumpers. The base address specified here must be in decimal, so if your base address is 0x0300, you should enter 768 which is the decimal equivalent of 300 hex. If you only have one Acces board in your system, you can leave the base address at 0 and DAQFactory will find the board for you. 5. Click OK to add your device. It will now appear in the Device Selection window. If you have more boards, click Add Device again and enter the appropriate information. Remember that with multiple boards, you must specify a unique device number, and you must specify the base address for each board. 6. When done, click Close. This configuration is saved with your document, so you will need to perform the above steps with every new document you create. Alternatively, you can save your document now before you have done anything and use it as a template for future documents. 7. At this point, you can create channels for your board using the channel table and the standard DAQFactory 17 Devices17.3 Acces I/O Device
314
methods. For each board type, there are different valid I/O types and channel numbers, but the device number in your channel should always match up with the device number you specified when you added the device in step 4 above.
Device Details:
PCI-AI12-16 PCI-AI12-16A These two boards both support analog inputs (in non-streaming mode), digital inputs and outputs: Analog Input: I/O type is A to D. Valid channel numbers are 0 to 15 in single ended mode, 0 to 7 in differential mode. There are two channel commands for setting gain and mode: Set Differential Mode: this can be set to either Yes or No. Set AD Gain Mode: there are 8 different gain options available. These are assignable to individual channels. Example: setting the gain. Setting differential mode is very similar. 1. Create a new channel in the channel table: Acces device type with a device number matching the device number you assigned to this board. I/O type is command. Channel # is 0. If you have multiple channel commands on this board, make sure each has a unique channel number. 2. Under Quick Note / Special / OPC for the channel a button should appear along the right side of the cell with three dots (...). Click on this button. 3. The Channel Parameters window will appear. From the drop down at the top of the window, select Set AD Gain Mode. 4. Two parameters will appear in the table. Channels takes a comma delimited list of channels you would like to set the particular gain for. Gain is the desired gain to set the listed channels to. Select from the list of possible gains. Choose your settings and click OK. 5. Click Apply to save your new channel. Simply creating the channel does not actually set the gain. To do this you must set the channel to something. It does not matter what. The simple way to do this is to right click on the new channel row and select Set Value, enter any value and click OK. You can also use components or sequences to set this channel. 6. Create a separate channel to set the gain for different channels, or a different setting. Remember that each must be set to a value to actually send the command to set gain. Digital Input / Output: I/O type is Dig In or Dig Out. Valid channel numbers are 0 to 3. Before using you may have to configure the port using the Set IO Type channel command. Example: setting the port direction. 1. Create a new channel in the channel table: Acces device type with a device number matching the device number you assigned to this board. I/O type is command. Channel # is 0. If you have multiple channel commands on this board, make sure each has a unique channel number. 2. Under Quick Note / Special / OPC for the channel a button should appear along the right side of the cell with three dots (...). Click on this button. 3. The Channel Parameters window will appear. From the drop down at the top of the window, select Set IO Type. 4. Two parameters will appear in the table. Channels takes a comma delimited list of channels you would like to set to a particular direction (input or output). Type is the desired direction to set the channels listed. Choose your settings and click OK. 5. Click Apply to save your new channel. Simply creating the channel does not actually set the port direction. To do this you must set the channel to something. It does not matter what. The simple way to do this is to right click on the new channel row and select Set Value, enter any value and click OK. You can also use components or sequences to set this channel.
17 Devices
315
6. Create a separate channel to set the direction for each port. Remember that each must be set to a value to actually send the command to set the direction. PCIDA12_2/4/6/8/16/8V/16V This series of boards support both D to A and Digital I/O. The number of valid channels varies depending on the board, but otherwise these boards are identical. Analog Output: I/O type is D to A. Valid channel numbers are 0 to one minus the number of the board. For example, the DA12_8 allows channel numbers from 0 to 7. Digital Input/Output: I/O type is Dig In or Dig Out. Before using you may have to configure the port using the Set Control Register channel command. This series of boards uses a standard 8255 type I/O chip. This means that the digital lines are split up into 4 ports. The first two, A and B, have 8 lines each, while the 3rd and 4th, CH and CL, have 4 lines. All lines on a given port must be configured as either an input or an output. Example: setting the port direction. 1. Create a new channel in the channel table: Acces device type with a device number matching the device number you assigned to this board. I/O type is command. Channel # is 0. If you have multiple channel commands on this board, make sure each has a unique channel number. 2. Under Quick Note / Special / OPC for the channel a button should appear along the right side of the cell with three dots (...). Click on this button. 3. The Channel Parameters window will appear. From the drop down at the top of the window, select Set Control Register. 4. Three parameters will appear in the table. ControlGroup should always be 0 for these boards. Ports can be A, B, CH, or CL as described above, and InOuts is where you will select the direction for the port. Choose your settings and click OK. 5. Click Apply to save your new channel. Simply creating the channel does not actually set the port direction. To do this you must set the channel to something. It does not matter what. The simple way to do this is to right click on the new channel row and select Set Value, enter any value and click OK. You can also use components or sequences to set this channel. 6. Create a separate channel to set the direction for each port. Remember that each must be set to a value to actually send the command to set the direction. PCIDIO-24S/48S/48JS/48HS PCIDIO-48/48J/48H This series of boards support digital I/O on up to 48 different lines. Digital Input/Output: I/O type is Dig In or Dig Out. Valid channel numbers are 0 to 23 or 0 to 47 depending on the board. Before using you may have to configure the port using the Set Control Register channel command. This series of boards uses standard 8255 type I/O chips. This means that the digital lines are split up into 4 ports. The first two, A and B, have 8 lines each, while the 3rd and 4th, CH and CL, have 4 lines. All lines on a given port must be configured as either an input or an output. The 48 channel versions of this board use two 8255 chips. Each chip is called a group. Example: setting the port direction. 1. Create a new channel in the channel table: Acces device type with a device number matching the device number you assigned to this board. I/O type is command. Channel # is 0. If you have multiple channel commands on this board, make sure each has a unique channel number. 2. Under Quick Note / Special / OPC for the channel a button should appear along the right side of the cell with three dots (...). Click on this button. 3. The Channel Parameters window will appear. From the drop down at the top of the window, select Set Control Register. 4. Three parameters will appear in the table. ControlGroup should be 0 for the first 24 channels, and 1 for
316
the second 24 channels. Ports can be A, B, CH, or CL as described above, and InOuts is where you will select the direction for the port. Choose your settings and click OK. 5. Click Apply to save your new channel. Simply creating the channel does not actually set the port direction. To do this you must set the channel to something. It does not matter what. The simple way to do this is to right click on the new channel row and select Set Value, enter any value and click OK. You can also use components or sequences to set this channel. 6. Create a separate channel to set the direction for each port. Remember that each must be set to a value to actually send the command to set the direction. PCIIRO8 PCIIRO16 This series of boards support digital outputs on relays. The current status of the relay can also be read back. Digital Output: I/O type is Dig Out. Valid channel numbers are 0 to 7 or 0 to 15 depending on the board. Because these are relays, you do not need to configure them as outputs. Relay feedback: I/O type is Relay Readback. Valid channel number are 0 to 7 or 0 to 15 depending on the board. This is an input that returns the actual state of the relay. PCIWDGCSM This board provides a watchdog timer to your system. Once initialized, you must read from a channel before a given timeout or your system will hard reboot. To setup the watchdog, create a D to A channel with any device # and channel #, and set that channel to the desired timeout value in counts. The minimum value is 32, though we recommend setting this much higher. Check the documentation that came with your board to determine how this count value corresponds to actual time, but 32 is around 0.1 seconds. Reading from an A to D channel on this board resets the counter. You must read from the A to D channel faster than the timeout interval or the computer will reset. Example: a timeout of 10 seconds is plenty reasonable for most applications. 1. Create two channels. Both are Acces device with a device number matching the device number you assigned to this board. The first is A to D I/O type, with any channel number. Give it a timing of 1 second. By giving the A to D channel a timing of 1, DAQFactory will reset the watchdog once a second if the system is not hung. The second is a D to A I/O type with any channel number. Click Apply to save your changes. 2. The channels are setup and DAQFactory is already looping and resetting the watchdog, but the watchdog has not been activated. To activate, set the D to A channel to 3200. The simple manual way to do this is to right click on the D to A channel in the channel table, and select Set To. When the window appears requesting a value, enter 3200 and click OK. The watchdog is now active, and assuming you have wired it correctly to the reset line of your computer, will reset your computer if DAQFactory hangs. You can also set the D to A value from components or from sequences if desired. 3. Save your document and close all other applications. Now, delete the A to D channel and click Apply. Within about 10 seconds your system should reboot. By deleting the A to D channel, DAQFactory stops resetting the watchdog, and eventually it resets the system.
17 Devices
317
RMM PMM QMM IR104 Details for each individual board type is provided below. In general, you must use the Device Configurator to setup your Diamon Systems board: 1. Open the device configurator: the easiest way is to select Quick - Device Configuration... from the main menu. 2. Click the Diamond configurator and click Select. The Diamond Device Selection window will be displayed:
This window allows you to identify a base address and device # for each Diamond board in your system. The base address is the address assigned to your board, usually through DIP switches or jumpers. The device # is an arbitrary number you will use to identify each board. The number simply has to be unique for each Diamond board in your system. When you first start, this window will be empty. 3. Click Add Device to add your first Diamond board:
4. A new window will appear. Select your Diamond board type. Enter in an arbitrary device number, zero is perfectly acceptable. Finally, enter the base address assigned to the board by its DIP switches or jumpers. You will have to check your manual with your board to determine the meaning of the switches or jumpers. The base address specified here must be in decimal, so if your base address is 0x0300, you should enter 768 which is the decimal equivalent of 300 hex. 17 Devices17.4 Diamond Systems device
318
5. Click OK to add your device. It will now appear in the Device Selection window. If you have more boards, click Add Device again and enter the appropriate information. Remember that with multiple boards, you must specify a unique device number, and you must specify the base address for each board. 6. When done, click Close. This configuration is saved with your document, so you will need to perform the above steps with every new document you create. Alternatively, you can save your document now before you have done anything and use it as a template for future documents. 7. At this point, you can create channels for your board using the channel table and the standard DAQFactory methods. For each board type, there are different valid I/O types and channel numbers, but the device number in your channel should always match up with the device number you specified when you added the device in step 4 above.
Device Details:
DMM32 DMM16 These two boards are identical except for the number of channels available. They support A to D in both streaming and software polled mode, D to A and Digital I/O. In the device configurator, you can configure two additional options. Click on the board in the Diamond Device selection window, and click Configure. The first parameter is gain, which determines the default gain of the A to D channels. The second is interrupt, which should be set to match the jumper settings on the board. This is only required if you are going to use streaming mode. Analog Input: I/O type is A to D. There are two ways to read analog inputs. The easy way is to use software polled mode. In this mode, you simply create your channels like any other device and specify a timing for each channel. The timing determines how often the analog input is polled for a new reading. This device driver is optimized and prefers to have analog inputs on the same timing interval. The maximum data rate is about 50 to 100hz in this mode. The other mode is streaming mode. In this mode, the acquisition rate is programmed into the board itself. DAQFactory will request data in blocks and therefore maximum data rates are much higher, up over 100,000hz depending on your computer. Setting this mode up requires a couple extra steps: 1. Create your A to D channels as you normally would, but set the timing for all of them to 0. 2. Create a new channel to act as the trigger to start streaming. The device type will be Diamond, device number will match the number you assigned in the device configurator, I/O type will be command, and the channel number will be a unique number, not used by other channel commands for this board. 3. Under Quick Note / Special / OPC for the channel a button should appear along the right side of the cell with three dots (...). Click on this button. 4. The Channel Parameters window will appear. From the drop down at the top of the window, select Streaming A to D. 5. Three parameters will appear in the table. The first two are the minimum and maximum channel to scan between. So if you specify 1 and 3, channels 1, 2 and 3 will be read. The last parameter is the rate. This is the sampling frequency in samples per second. This must be less than the maximum sample rate for the card (see your manual). If you are scanning across three channels, the actual interval between subsequent scans is the sampling frequency divided by 3. Choose your settings and click OK. 6. Click Apply to save your new channel. Simply creating the channel does not actually start streaming. To do this you must set the channel to something. It does not matter what. The simple way to do this is to right click on the new channel row and select Set Value, enter any value and click OK. You can also use components or sequences to set this channel. Once started, the device will stream new readings and the values will go into the A to D channels you created in step 1. 7. You may want to repeat the steps 2 through 5 and create a channel with the Stop Streaming A to D. This command has no parameters, but when set will stop the streaming if running. There is also a similar command to Streaming A to D called Burst A to D. This is very similar to streaming, but also has a parameter for the total number of desired samples. Once those samples have been acquired, the streaming stops.
17 Devices
319
Using a channel command you can also set the gain of the A to D channels. All the A to D channels must have the same gain. The channel command is A to D Gain Setting, and is setup very similar to the stream mode just described. Analog Output: I/O Type is D to A. Analog output on the DMM boards is simply a matter of creating a channel and setting it to the correct value. The acceptable output values are 0 to 4095. Since the range of the D to A is determined by a jumper which cannot be read by DAQFactory, you must specify raw counts when setting a D to A output. You can use a conversion to make this easier. For example, if you have the D to A set to 0 to 5V range, the conversion would be Value / 5 * 4095. Digital Input / Output: I/O type is Dig In or Dig Out. Before using you may have to configure the port using the Set Port Direction command. By default, all ports are set as inputs. This series of boards uses a standard 8255 type I/O chip. This means that the digital lines are split up into 4 ports. The first two, A and B, have 8 lines each, while the 3rd and 4th, CH and CL, have 4 lines. All lines on a given port must be configured as either an input or an output. Example: setting the port direction. 1. Create a new channel in the channel table: Diamond device type with a device number matching the device number you assigned to this board. I/O type is Command. Channel # is 0. If you have multiple channel commands on this board, make sure each has a unique channel number. 2. Under Quick Note / Special / OPC for the channel a button should appear along the right side of the cell with three dots (...). Click on this button. 3. The Channel Parameters window will appear. From the drop down at the top of the window, select Set Port Direction. 4. Four parameters will appear in the table, one for each port. For each, you can specify whether the port is an input or output. Choose your settings and click OK. 5. Click Apply to save your new channel. Simply creating the channel does not actually set the port direction. To do this you must set the channel to something. It does not matter what. The simple way to do this is to right click on the new channel row and select Set Value, enter any value and click OK. You can also use components or sequences to set this channel. RMM The RMM is an analog output board that also includes an 8255 digital I/O chip. This board supports analog output, digital input and digital output. Analog Output: I/O Type is D to A. Analog output on the DMM boards is simply a matter of creating a channel and setting it to the correct value. The acceptable output values are 0 to 4095. Since the range of the D to A is determined by a jumper which cannot be read by DAQFactory, you must specify raw counts when setting a D to A output. You can use a conversion to make this easier. For example, if you have the D to A set to 0 to 5V range, the conversion would be Value / 5 * 4095. Digital Input / Output: I/O type is Dig In or Dig Out. Before using you may have to configure the port using the Set Port Direction command. By default, all ports are set as inputs. This series of boards uses a standard 8255 type I/O chip. This means that the digital lines are split up into 4 ports. The first two, A and B, have 8 lines each, while the 3rd and 4th, CH and CL, have 4 lines. All lines on a given port must be configured as either an input or an output. Example: setting the port direction. 1. Create a new channel in the channel table: Diamond device type with a device number matching the device number you assigned to this board. I/O type is Command. Channel # is 0. If you have multiple channel commands on this board, make sure each has a unique channel number. 2. Under Quick Note / Special / OPC for the channel a button should appear along the right side of the cell with three dots (...). Click on this button. 3. The Channel Parameters window will appear. From the drop down at the top of the window, select Set Port Direction. 4. Four parameters will appear in the table, one for each port. For each, you can specify whether the port
320
is an input or output. Choose your settings and click OK. 5. Click Apply to save your new channel. Simply creating the channel does not actually set the port direction. To do this you must set the channel to something. It does not matter what. The simple way to do this is to right click on the new channel row and select Set Value, enter any value and click OK. You can also use components or sequences to set this channel. PMM The PMM is a digital output board with relays. This board only supports digital output, I/O type Dig Out. Valid channel numbers are 0 to 15. No configuration is required. QMM The QMM is a counter board. It operates in one of two modes. The first mode cascades the 10 16bit counters into 5 32 bit counters. The second mode uses gating to measure the duration of a TLL pulse. The mode is selected by creating a D to A channel #0. Setting this channel to 0 selects the cascade mode. Setting it to 1 selects the gating mode. To start reading counts, create channels with I/O type Counter, channel #0 to 4 corresponding to the 5 measurements. Only one of these channels needs timing information as all the counters are read at once. The actual counts returns into these channels. In addition, you can create a channel with I/O type Count Duration, channel # 0, which will return the precise amount of time spent counting in nanoseconds. This will vary slightly from read to read and can be used to normalize your counts. IR104 The IR104 is a digital output board. It only supports the Dig Out I/O type. Valid channel #'s are 0 to 19.
17 Devices
321
2. Click the ICP7000 configurator and click Select. The ICP7000 Device Selection window will be displayed:
3. Select the baud rate for communication. Although you can communicate with multiple devices on different COM ports, you can only communicate at one baud rate on all ports. 4. Click Add Device to add your first device. A new window will display:
5. Select your device and then fill in the three parameters. The device # is a arbitrary number that you will use in DAQFactory to identify this unit. It should be a unique number for each unit. The Com port determines which com port the unit is connect to. The address is the ID address assigned to the unit by the ICP configuration utility. You will probably have to run that program first to determine the addresses of your units. 6. Click OK to add your unit. It will now appear in the Device Selection window. If you have more units, click Add Device again and enter the appropriate information. Remember that with multiple units, you must specify a unique device number. 7. When done, click Close. This configuration is saved with your document, so you will need to perform the above steps with every new document you create. Alternatively, you can save your document now before you have done
322
anything and use it as a template for future documents. 8. At this point, you can create channels for your board using the channel table and the standard DAQFactory methods. Both the 7017 and 7018 are analog input modules. Both of these units support the Analog Input I/O type. In addition to the analog input, there is a single channel command for setting the range called Set Range. Example: setting the gain. 1. Create a new channel in the channel table: ICP7000 device type with a device number matching the device number you assigned to the unit you would like to set the range for. I/O type is Command. Channel # is 0. If you have multiple channel commands on this unit, make sure each has a unique channel number. 2. Under Quick Note / Special / OPC for the channel a button should appear along the right side of the cell with three dots (...). Click on this button. 3. The Channel Parameters window will appear. From the drop down at the top of the window, select Set Range. 4. One parameters will appear in the table: New Range is the desired gain to set the unit to. Select from the list of possible gains. Choose your settings and click OK. The all ranges displayed may not be supported by your unit. The 7018 supports more ranges than the 7017, but both will list the same options. 5. Click Apply to save your new channel. Simply creating the channel does not actually set the gain. To do this you must set the channel to something. It does not matter what. The simple way to do this is to right click on the new channel row and select Set Value, enter any value and click OK. You can also use components or sequences to set this channel.
17 Devices
323
returned by OpenLabJack. IOType and Channel can be the constants for a particular task. Since DAQFactory does not support indirect pointers, the Value, and x1 parameters only hold values used for setting outputs or parameters. Results are returned by GetResult(). Only the first three parameters are required. DoubleToStringAddress(Number, @String, HexDot): This function is identical to the UD equivilent. eAIN(D#, ChannelP, ChannelN, @Value, Range, Resolution, Settling, Binary, R1, R2): This function is identical to the UD equivilent. eDAC(D#, Channel, Voltage, Binary, R1, R2): This function is identical to the UD equivilent. eDI(D#, Channel, @State): This function is identical to the UD equivilent. eDO(D#, Channel, State): This function is identical to the UD equivilent. eGet(D#, IOType, Channel, @Value, x1): This function combines AddRequest, GoOne, and GetResult into one call. It obviously can only perform one task at a time, but for simple tasks can be easier to deal with. Like AddRequest(), only the first three parameters are required. So you could do this to read an analog value: eGet(1,LJ_ioANALOG_INPUT, 1, @result) ePut(D#, IOType, Channel, Value, x1): This function combines AddRequest, GoOne, and GetResult into one call, but designed for setting a parameter. It obviously can only perform one task at a time, but for simple tasks can be easier to deal with. ErrorToString(ErrorCode, @String): This function is identical to the UD equivilent. eTCConfig(D#, EnableTimers, EnableCounters, TCPinOffset, TimerClockBaseIndex, TimerClockDivisor, TimerModes, TimerValues, R1, R2): This function is identical to the UD equivilent. eTCValues(D#, ReadTimers, UpdateResetTimers, ReadCounters, ResetCounters, @TimerValues, @CounterValues, R1, R2)",Tip): This function is identical to the UD equivilent. GetDriverVersion(): This is the simplest function and simply returns the version number of the driver (i.e. 2.04) GetFirstResult(D#, @IOType, @Channel, @Value, @x1, @UserData): This function is identical to the UD equivilent. GetLastError(D#): returns the error code of the last error on the given device. The error codes are described in the labjackud.h file of the UE9 programming library. GetLastStreamError(D#): returns the error code of the last error generated by the stream retrieval routine. Since stream data retrieval is done internally, this is the only way to see any errors occurring in stream. The error codes are described in the labjackud.h file of the UE9 programming library. GetNextError(D#, @IOType, @Channel, [@Error]): Gets the next error from the list of errors from the previous GoOne() on the given D#. Repetitive calls will cycle through the list. Repeat until LJE_NOERROR is returned. This function returns the error, or LJE_NOERROR, but also allows you to optionally provide a reference to a variable to also receive the error. This allows you to put this function inside the while() expression and assign the error to a variable for further processing at the same time. GetNextResult(D#, @IOType, @Channel, @Value, @x1, @UserData): This function is identical to the UD equivilent. GetResult(D#, IOType, Channel, @Value): Gets the result for the given operation. Like AddRequest, IOType and Channel can be constants or numbers. GoOne(D#): Performs all the AddRequests that have queued up on the given device since the last call to GoOne(). OpenLabJack(Device Type, ConnectionType, Address, FirstFound, @D#): this function opens the specified LabJack if not already open and returns a device number in @D# that is used by all other functions and channels. This is not quite the same as the handle returned by the regular C function, but should essentially be treated the same. Use this function if you need to dynamically open LabJack's at runtime without using the device configurator. Device Type and Connection Type take constants such as LJ_dtUE9 and LJ_ctUSB. Address is a string. First found is either 0 or 1, where 1 means find first found and ignore the specified Address. ResetLabJack(D#): This function is identical to the UD equivilent. 17 Devices17.7 LabJack UE9 / U6 / U3
324
StringToConstant(String): This function is identical to the UD equivilent. StringToDoubleAddress(String, @Number, HexDot): This function is identical to the UD equivilent.
Device Details:
The LabJack U12 requires 20ms to perform any acquisition block. An acquisition block is either reading of up to 4 A to D channels, setting either or both D to As, setting / reading the digital outputs, and reading the counter. Therefore, do not make your Channel Timing values less than 0.02 seconds, as the LabJack will not be able to keep up. If you are using more than one acquisition block, your Timing values will have to be corresponding larger. DAQFactory, is however, multithreaded, so while it takes 20ms to communicate with a single LabJack, if you have two LabJacks, you can communicate with the second LabJack at the same time, thus increasing the maximum throughput. This follows for 3, 4, or more LabJacks. In order to do this however, you must give the Channels on the different LabJacks a different Timing and Offset parameter. The difference can be as small as 0.001 if you would like. This is actually one of the uses for the Offset parameter. Analog Input: There are two types of analog inputs with the LabJack, single ended and differential. All are 12 bit and return measurements in volts. Single ended inputs are wired into AI0 through AI7 and GND and provide 8 inputs. Differential inputs are wired in pairs, AI0-AI1, AI2-AI3, AI4-AI5, AI6-AI7. The GND terminal is not used. Because two lines are used for each differential input, the LabJack only provides 4 differential inputs. Differential inputs have two advantages over single ended. First, they cancel possible noise in your wiring, and second they have programmable range. If you do not need to more than 4 inputs, we recommend using the differential inputs. Example - Reading an analog input at 1 hz. See under Streaming Analog Input below for rates faster than 50hz. 1. Starting from a blank document with a single LabJack plugged into your computer, click on CHANNELS: in the workspace to display the channel table. Click on Add to add a blank row to the table. 2. Enter a simply channel name like Input0 for the channel name column. For device type, select LabJack_U12. For device number enter 0. Select A to D for I/O type. 3. If you want to read one of the eight single ended inputs, enter 0 through 7 for channel number, corresponding to AI0 through AI7. For differential inputs, use 8 through 11, corresponding to AI0-AI1, AI2AI3, AI4-AI5, and AI6-AI7. In this example, select one of the differential inputs, say 8. 4. The next column is timing which determines how often the analog channel is read. The LabJack has a maximum software polled rate of 50hz, so the timing column should never have a value less than 0.02. As you use more and more inputs and outputs, the minimum timing value will grow. If you are getting C1038 Timing Lag errors then your timing values are probably too small. For now, leave it at 1.00. 5. Click Apply to save your new channel. DAQFactory will immediately start reading from the LabJack. The LED on the LabJack unit should flash indicating DAQFactory is communicating with it. 6. To quickly see the data, click on the + sign next to CHANNELS in the workspace, then click on your new channel that will appear when the tree expands. This will display the channel view. Click on the Graph tab. You should see a graph of your data. Alternatively, click on the Table tab to see the actual values in tabular form. Example - Setting the range on a differential channel. Range is not an option with single ended inputs. 2011 AzeoTech, Inc.
17 Devices
325
Range is set using a channel command. 1. Create a new channel in the channel table: LabJack_12 device type with a device number of 0 (assuming you have only one LabJack). I/O type is Command. Channel # is 0. If you have multiple channel commands on this LabJack, make sure each has a unique channel number. 2. Under Quick Note / Special / OPC for the channel a button should appear along the right side of the cell with three dots (...). Click on this button. 3. The Channel Parameters window will appear. From the drop down at the top of the window, select Gain Settings. 4. There are two parameters that will appear in the table. Channels takes a comma delimited list of channels to set the gain for. Since single ended channels do not have gain, valid channels are 8 through 11. For example 8,9,10,11 would set all the channels to the same gain. The second parameter is the Gain. Select from the drop down list the desired range. Click OK. 5. Click Apply to save your new channel. Simply creating the channel does not actually set the gain. To do this you must set the channel to something. It does not matter what. The simple way to do this is to right click on the new channel row and select Set Value, enter any value and click OK. You can also use components or sequences to set this channel. Analog Output: The U12 supports two 10 bit analog output channels. These are both 0 to 5 volt outputs. Example - Creating and setting an analog output channel. 1. Starting from a blank document with a single LabJack plugged into your computer, click on CHANNELS: in the workspace to display the channel table. Click on Add to add a blank row to the table. 2. Enter a simply channel name like Output0 for the channel name column. For device type, select LabJack_U12. For device number enter 0. Select D to A for I/O type. 3. The two analog output channels of the LabJack are numbered 0 and 1 corresponding to the AO0 and AO1 pins on the device. Enter the desired number in the channel column. 4. Click Apply to create your new channel. Once you have the channel created you can now set it to a value. The quick way to do this is to right click on the new channel in the channel table and select Set Value. This will display a window where you can type in your voltage setting. When you click OK, the analog output will be set to that voltage, provided it is between 0 and 5. You can also set this value using various page components or in an automated sequence. This is described in the rest of the DAQFactory documentation. Digital I/O: The U12 supports 20 channels of Digital I/O numbered 0 to 19. 0 through 3 are the front panel IO0 though 3 pins. 4 through 19 are the D0 through D15 pins on the DB25 on the side of the unit. Each can be configured for either input or output by simply assigning it to a DigIn or DigOut Channel. The current state of a DigOut can be read back using the same DigIn channel once the DigOut is set. Until a DigOut is set, the channel is assumed to be an input. Use the Set I/O to Dig In command to revert a channel assigned as an output back to an input. Example - To read a digital input, simply follow the example provided for the analog input, but use the Dig In I/O type instead. Example - To create a digital output, simply follow the example provided for the analog output, but use the Dig Out I/O type instead. When you get to step 4, the Toggle option will be used in place of Set Value, as digital outputs only have two valid values, 0 and 1. Example - All the I/O pins on the LabJack can be input or output. When the LabJack is first plugged in, all the pins are set as inputs. Once you set a pin to a value using the Dig Out I/O type, it is considered an output. To switch it back to a digital input: 1. Create a new channel in the channel table: LabJack_12 device type with a device number of 0 (assuming you have only one LabJack). I/O type is Command. Channel # is 0. If you have multiple channel commands on this LabJack, make sure each has a unique channel number. 2. Under Quick Note / Special / OPC for the channel a button should appear along the right side of the cell with three dots (...). Click on this button.
326
3. The Channel Parameters window will appear. From the drop down at the top of the window, select Set I/O to Dig In. 4. There is one parameter that will appear in the table. The channels parameter takes a comma delimited list of channels to set to digital input, for example 0,1,2,3 would refer to the front IO0 through 3 pins. Select your channels and click OK. 5. Click Apply to save your new channel. Simply creating the channel does not actually set the digital channel. To do this you must set the channel to something. It does not matter what. The simple way to do this is to right click on the new channel row and select Set Value, enter any value and click OK. You can also use components or sequences to set this channel. Counter: The U12 supports a single 1 Mhz counter numbered 0. Since there is only one counter, all data comes back on channel number 0. By default, the counter is reset every time it is read. There is a channel command associated with this I/O type that allows you to keep the counter from resetting. Example - To read the counter, simply follow the example provided for the analog input, but use the Counter I/O type instead. Only channel 0 is supported. Example - Setting the counter to not reset: 1. On the row of the counter channel that you created, under Quick Note / Special / OPC for the channel a button should appear along the right side of the cell with three dots (...). Click on this button. 2. The Channel Parameters window will appear. From the drop down at the top of the window, select Reset. 3. The only parameter for this command is Reset?. Select Yes or No then click OK. 4. Click Apply to save your changes to the channel. The effect of the change is immediate. Temperature / Humidity Probe (EI-1050): The EI-1050 is a digital temperature / humidity probe. To query this device, create two channels, both with I/O type "Special", one with channel #0, and one with channel #1. Channel #0 is the temperature in degrees C, while channel #1 is the humidity. You must put a timing on channel #0 as this triggers the read of both sensors. Streaming Analog Input: The U12 has the ability to stream its inputs instead of being polled for data. When streaming, the internal clock of the LabJack determines when data is acquired and the data is passed back to DAQFactory in blocks. This allows much faster data rates than would be possible using software polled mode described above. Unfortunately, when the LabJack is streaming you cannot do anything else with that LabJack. If you have two LabJacks you can work with the channels on the second LabJack, but on the streaming LabJack you should have the Timing parameter for all its channels set to 0. There are three different modes of streaming: Continuous Streaming: This mode causes the LabJack to continuously stream the requested inputs until manually stopped. It is initiated with the Start Stream channel command, and stopped with the Stop Stream channel command. The maximum data rate is 1200 samples per second. Example: 1. Starting from a new document, go to the channel table by clicking on CHANNELS: in the workspace. 2. Click the Add button to add a new row. Call the new channel StartStream, device type LabJack_U12, device number 0, I/O type Command, channel #0. 3. Under Quick Note / Special / OPC for the channel a button should appear along the right side of the cell with three dots (...). Click on this button. 4. When the parameter window appears, select Start Stream from the drop down at the top. 5. Four parameters will appear in the table: a. Stream Channels: this takes a comma delimited list of channels to stream. You can enter up to four channels. For this example, enter 8,9,10,11. This will stream the 4 differential channels. b. Stream Gains: this takes a comma delimited list of gain numbers (0-7) for each channel listed. You can leave this blank to use the default gains. This does not apply to single ended channels. For this example, leave it blank.
17 Devices
327
c. Stream Scan Rate: enter the desired scan rate. A scan is the reading of all channels listed under Stream Channels. Since the maximum rate is 1200 samples per second, the maximum scan rate is 1200 / number of channels read. So if you are streaming four channels, the maximum scan rate is 300. For this example, enter 100. d. Stream Counter: you can optionally stream the counter reading. This uses three of the four slots available for channels, so you can only stream one other A to D channel when streaming the counter. Data comes in under the Counter I/O type, channel 0. For this example, select No. 6. Click OK to close the parameters box, then click Duplicate to duplicate the channel you just created. Give the new row the name StopStream. Leave all the parameters as they are, but click on the Quick Note / Special / OPC button again to display the parameters window. 7. This time, select Stop Stream. There are no parameters for this command, so hit OK, then Apply to save your two new channels. 8. Simply creating these channels does not actually perform streaming. To do this you must set the channels to something. It does not matter what. The simple way to do this is to go to the Command/Alert window and in the small box type in StartStream = 0. This should start the streaming. The LED on your LabJack will flash rapidly. You can also use components or sequences to set this channel and start streaming. 9. Even though the streaming is running, the data is going no where. We have to create channels to accept the data. In the channel table, click Add. In the new row, call the new channel AI8, device type LabJack_U12, device number 0, I/O type A to D, channel #8. Set the Timing to 0. This is important or DAQFactory will try and read the channel in software polled mode and this will stop the streaming. 10. You can optionally create channels for 9, 10 and 11 which are also streaming. When done, click Apply. 11. To quickly see the data coming in, click on the + next to CHANNELS: in the workspace, then click on the AI8 channel. This will display the channel view for that channel. Click on the Graph page to view a graph of the incoming data, or optionally, click on Table to see the readings in tabular form. You can now use the rest of the DAQFactory page components, such as the 2D graph, to better display your data. Burst Streaming: This mode causes the LabJack to stream for a preset amount of time. This mode allows for faster data rates, up to 8192 samples per second, but can only take 4096 samples at a time. It is initiated with the Burst Mode channel command. Example: 1. Starting from a new document, go to the channel table by clicking on CHANNELS: in the workspace. 2. Click the Add button to add a new row. Call the new channel StartBurst, device type LabJack_U12, device number 0, I/O type Command, channel #0. 3. Under Quick Note / Special / OPC for the channel a button should appear along the right side of the cell with three dots (...). Click on this button. 4. When the parameter window appears, select Burst Mode from the drop down at the top. 5. Six parameters will appear in the table: a. Burst Channels: this takes a comma delimited list of channels to burst stream. You can enter up to four channels. For this example, enter 8,9,10,11. This will stream the 4 differential channels. b. Burst Gains: this takes a comma delimited list of gain numbers (0-7) for each channel listed. You can leave this blank to use the default gains. This does not apply to single ended channels. For this example, leave it blank. c. Burst Scan Rate: enter the desired scan rate. A scan is the reading of all channels listed under Stream Channels. Since the maximum rate is 8192 samples per second, the maximum scan rate is 8192 / number of channels read. So if you are streaming four channels, the maximum scan rate is 2048. For this example, enter 1000. d. Burst Number of Scans: enter the desired number of scans to perform. The maximum number of
328
samples is 4096, so if you are sampling 4 channels per scan, the maximum number of scans is 1024. For this example, enter 100. e. Burst Trigger: You can optionally have the LabJack use one of the IO pins as a trigger for the burst. In this row, you can select which IO pin to use, or select None or leave blank for no triggering. For this example, just leave this field blank. f. Burst Trigger State: If you specified a burst trigger, you will need to specify whether you want to trigger when the indicated IO pin goes high (5V), or low (0V). For this example, leave the field blank. 6. Click OK to close the parameters box. Now we need to create channels to receive the data. In the channel table, click Add. In the new row, call the new channel AI8, device type LabJack_U12, device number 0, I/O type A to D, channel #8. Set the Timing to 0. This is important or DAQFactory will try and read the channel in software polled mode and this will stop the streaming. 7. You can optionally create channels for 9, 10 and 11 which will also burst stream. When done, click Apply. 8. In this example, we will create some screen components for triggering the burst and graphing the data on AI8. Go to the page view by clicking on Page_0 in the workspace. The page view will be a blank white screen. 9. Right click in the upper left corner of the white space and select Buttons-Button. Right click on the new component and select Properties... 10. In the Text property, enter Burst. Then go to the Action page and select Toggle Between. Next to Action Channel enter StartBurst. For the two toggle between parameters, enter 0 and 0. It does not matter what we set the StartBurst channel too, so we are just going to set it to 0 every time the button is clicked. Click OK. 11. Right click in another area of the screen and select Graphs - 2D Graph. You may want to resize the graph that appears by holding down the Ctrl key and dragging one of the black squares surrounding the graph. 12. Right click on the graph and select Properties... 13. Under Y Expression enter AI8 and then click OK. 14. Now click on the button you created to start burst mode. The burst mode only lasts 0.1 seconds, so it will go quick. The graph should update, but might be out of range. Right click on the graph and select AutoScale - Y axis to fix this. PreTrigger Streaming: This allows you to run in stream mode, but only log data around a certain event, either a threshold crossing for an analog channel, or a digital channel going high or low (or both). It is initiated with the PreTrigger Stream channel command and can be stopped with the Stop Stream channel command. Since it uses continuous streaming, the maximum data rate is 1200 samples per second. The setup is very similar to burst and stream. Here are the parameters of the channel command that are different than the Start Stream: Trigger Channels: takes a comma delimited list of channels to monitor. These channels must be among the channels listed in Scan Channels. Trigger Thresholds: takes a comma delimited list of voltage readings above or below which the trigger will have said to occur. There should be one threshold for each Trigger Channel listed. Reset Threshold: the value above or below which the trigger is reset and another trigger can occur. For no historesis, set these values to the same values as the Trigger Thresholds. Trigger Types: determines whether the trigger occurs above or below the threshold. Digital Trigger Channels: takes a comma delimited list of digital channels to use as triggers. Only channels 0-3 can be used (IO0-IO3). Digital Trigger States (trigger on 1 or 0): takes a comma delimited list, one item for each digital trigger. If the item is 1, then the digital trigger occurs when the signal goes high. If the item is 0, then the digital trigger occurs when the signal goes low. Pretrig Samples: the number of samples before the trigger event occurs to log. Can be 0.
17 Devices
329
PostTrig Samples: the number of samples after the trigger event occurs to log (including the trigger value). Must be >= 2. Immediate Retrigger: If yes, then a reset followed by a trigger while the PostTrig samples are being logged results in the posttrig sample counter being reset to Posttrig Samples. If no, then a retrigger during posttrig acquisition does nothing. Digital triggers do not need to be reset, a digital signal that remains in its trigger state will continually trigger. Display Incoming?: If yes, then data from the stream will be output to channels of I/O type Special throughout the PreTriggering. This allows you to view the data being taken at all times. Simply create new Channels with I/O type Special, and channel numbers matching the A/D channels. Some notes about PreTriggering: Data is not logged until all the PostTrig samples are taken. If the type is Above, the trigger occurs when reading > threshold and resetting occurs when reading < reset threshold. (and vice-versa) You can trigger off of any, or all of the channels being streamed. Each trigger must be independently reset before that particular trigger will refire. However, if a trigger on one channel fires, but is not reset, then a trigger on another channel fires, the second trigger will be recognized. Digital triggers do not need to be reset. They will continually refire if they remain in the trigger state. This allows you to use digital lines to start and stop logging. NOTE: while doing high speed acquisition, you cannot do any other I/O on the LabJack. Any attempt will stop the high speed acquisition. If you have multiple LabJacks, you can perform high speed acquisition on only one LabJack. You can however, perform I/O on the other LabJacks while the high speed acquisition is occurring. Note: when taking and logging data faster than 20hz you'll need to set the Alignment Threshold parameter of your logging set to 0 to avoid missing data points in your logging set. Sequence optimization channel commands: The following channel commands are typically used in sequences to utilize the LabJack in the most efficient manner: Read Digital Block: Reads a block of digital channels in one call to the LabJack. Put a comma delimited list of desired digital channels (0-19) in the channels parameter. Write Digital Block: Writes a block of digital channels in one call to the LabJack. Put a comma delimited list of desired digital channels (0-19) in the channels parameter, and a corresponding comma delimited list of 0's or 1's to output to each channel in the Values parameter. Write Digital Block Single Value: Writes a block of digital channels in one call to the LabJack. Put a comma delimited list of desired digital channels (0-19) in the Channels parameter. The Value parameter takes a single value that is bitwise parsed to each digital output channel. The first channel in the list is the LSB, the last, the MSB. So, if you put 0,3,5,7 in the Channels parameter, and 9 in the Value parameter, you would get a 1 output to channels 0 and 7, and a 0 output to channels 3 and 5. This command is very useful if you put the word "Value" in for the Value parameter. Then the outputs are set to whatever you set this channel command to. Read Analog Block: Reads a block of analog channels in one call to the LabJack. Put a comma delimited list of desired analog channels (0-11) in the Channels parameter. Write Analog Block: Writes a block of analog channels in one call to the LabJack. Put a comma delimited list with two values in the Values parameter. The first value in the list is output to AO0, the second to AO1.
330
It provides A/D, D/A, Dig In/Out, Counter (in pulse count mode), and Temperature (under Special I/O Type) support. For cards that support hardware paced acquisition, the A/D channels are hardware paced at 250hz per channel and then averaged to your desired timing. This means that if your channel has a Timing of 0.5 seconds, you will get a reading twice a second, but each value will be the average of 125 reads. This results in much lower noise without using extra computer processor power. For boards not supporting hardware paced timing (or pacing at this rate), this device driver will read A/D channels in the standard single shot mode. The device number of all channels created for the MComputing device must match the board number specified in InstaCal. This allows you to communicate with multiple MComputing boards in a single system.
A to D: As stated, the default mode for A to D for boards that support hardware paced data acquisition is to
sample all channels at 250hz and average the data down to the desired read interval. For boards that do not support hardware paced acquisition, simply one-shot software polling is done. You can switch off of hardware paced mode by using the "Stop Background" Channel Command described below. For boards that support a channel/gain queue, you can set each individual channel with a different gain. For boards without a channel/gain queue, the gain setting for channel 0 is used. When running in software polled mode, each channel can have a different gain setting, even on boards without the queue. This is one good reason for executing the Stop Background command and running in software polled mode instead.
Dig In / Dig Out: These channels contain special parameters that are accessed the same way as the Channel
Commands, but the I/O Type remains as either Dig In or Dig Out. The parameter determines whether the channel number you are specifying belongs to the AUXPORT or to FIRSTPORTA series. If you are using AUXPORT, then you do not need to configure the port (it comes preconfigured). Before using the FIRSTPORTA series you must use the DConfig Channel Command to configure the digital port direction. The channel number corresponds to the bit number starting with FIRSTPORTA and rolling into FIRSTPORTB, then FIRSTPORTCL, etc... So, for example, channel 24 is the first bit of SECONDPORTA.
Counter: The counter I/O type simply performs a cbCIn32 command and returns the value. You must set up
your counters using the proper Channel Commands before you will get any results.
Special: The special I/O type for this driver is for use with Measurement Computing's temperature boards. There
are some Channel options available (similar to the digital I/O types and accessed just like a Channel Command) for selecting the units and whether the signal should be filtered.
Channel Commands: Set AD Gain: This sets the gain for one or multiple channels. Not all gains are supported by all boards.
Depending on the mode you are using to read you A/D channels, your gain settings may not have an affect (see the A to D description above). To set the same gain for multiple channels, list all the channels separated by commas. If you specify "Value" for the gain, you can enter the MComputing gain code directly.
Set DA Gain: This sets the gain for one or multiple D to A channels. Not all gains are supported by all boards.
To set the same gain for multiple channels, list all the channels separated by commas.
DConfig: This configures the digital ports on your board to be either input or output. With the exception of the
AUXPORT, all digital ports of your boards must be configured for either input or output before use.
Stop Background: This command is typically used with the more advanced commands listed below, but can
also be used to cancel the automatic hardware paced acquisition to allow for different gain settings for different channels on boards that don't support the channel / gain queue. There are no parameters for this Command.
17 Devices
331
channels, but you would put a different offset for each (0.1,0.25,0.4,0.55,0.7,0.85) By not assigning a Timing and Offset to a channel for this device that is the same as any other devices you might be reading, you will also eliminate any delay in reading those other channels. This device has many settings that are all available through Channel commands. There use is pretty self explanatory. The commands available are listed here: Set Set Set Set Set Set Set Set Set Set Powerline Frequency Temperture Units Channel Mode Current Source Range Shunt Value Open TC Detection Ground Reference CJC RTD Ice Point
Device Configurator:
DAQFactory offers a configurator for very quickly selecting OPC tags and creating channels to access these tags from within DAQFactory. You can access the configurator by selecting Quick Device Configuration... from the main menu. If you do not have any OPC channels yet, you will be prompted with a window to find your OPC server:
332
If you are trying to find a remote server, Windows sometimes does not keep an accurate listing of the available networked computers. If the remote computer you need does not appear, you can click on the Add Host button to manually enter the name of the remote host. After selecting, the configurator window will appear:
At top of the wizard dialog is displayed the currently selected server. You can change the selected server by clicking the Find Server button to the right. In order to support remote connections, the server is indicated using a GUID. Although not that human friendly, this unique identifier works well over a network.
17 Devices
333
The rest of the window is split into two tables that display the input tags and output tags for the currently selected server. Above each table is the Browse button that allows you to browse for tags on the currently selected server. This will open up another dialog box with the tags on the server. Simply double click on the desired tags and they are added to the list. You do not need to close the browse dialog box with each tag. You can add multiple tags very quickly this way. When a new tag is added a channel name is produced from the tag name by removing invalid characters (such as the period that is typically in OPC tags). You can use this default channel name, or enter your own in the table. For your convenience, the most recently polled value for each Channel is displayed in the Value column of the Input Tags table. You can also set output tags by entering the output value in the Value column of the Output Tags table.
Device Details:
It is strongly recommended that you use the device configurator for specify OPC tags. There are a few details that need to be mentioned though about the channels that are created: By default, all input tags are setup in asynchronous mode. This means that the OPC server only sends a new value to DAQFactory when that value changes up to a maximum rate of 10 updates per second. If the value does not change, no new data is created. This may result in a blank space in the data log. To avoid this, specify Duplicate Last Value in your logging set. Async mode is definitely the preferred mode as it is more efficient. For fast changing systems where you do not need 10 hz update speeds, you may want to set your channels into synchronous mode. In this mode, the Timing parameter of each channel determines when the value is read. The value is read whether it has changed or not. You can switch any channels to sync mode by changing the I/O type of the channels. Remember to set the Timing parameter as well to the desired polling interval. For string tags, you will need to change the I/O type of the channel to String Read. String reading is async only. For array tags, you will need to change the I/O type of the channel to Array Read. Array reading is async only.
334
the PC (and it may be many miles away) in the DAQFactory channel setup assign the Device to 7. Physical Interface. The physical serial port connection from the PC running DAQFactory must be made to the RFScada device that is configured as the master, as it is the only device in an RFScada network with access to all of the RFScada network registers. The serial port connection may either be RS-232 or RS-485 (2 wire hardware automatic). All serial port parameters except the COM port are assigned automatically. DAQFactory Serial Port Selection. Before any DAQFactory access to the RFScada network is possible the COM port must be selected from within DAQFactory. A DAQFactory device command may be used to do this. First create a DAQFactory channel with the following properties, Device Type: RFScada; Device Number: 0; I/O Type: Command. Now when this channel is set to a value from within DAQFactory the value will become the serial port used for RFScada access. So simply assign a value of 1 to 16 to set the connected COM port. Once set the COM port is typically never changed, so it may easily be set once in the initial startup sequence. DAQFactory Serial Port Status. There are many possible serial port errors that could occur during communication between the PC running DAQFactory and the RFScada units, for example the user could attempt to select a non existent serial port or the serial cable could be unplugged. The status of serial port communications may be monitored from within DAQFactory and of course it may be used to initiate alarms and warnings. To access the serial port status set up a channel as Device Type: RFScada; Device Number: 0; I/O Type: Special; Channel: 1. Reading the channel will return the serial port state, with the following meanings: 0 Correct operation 1 to 4 Failed to initialize 5 9 Internal initialization errors 10 & 11 Failed to read correctly 12 to 14 Failed to write correctly RFScada Radio Network Status. If there are multiple physical RFScada units in the system then the RFScada units will continually communicate amongst themselves via the built in radios. The status of this radio network may be monitored from DAQFactory, and of course it may be used to initiate alarms and warnings. To access the RFScada radio network status set up a channel as Device Type: RFScada; Device Number: 0; I/O Type: Special; Channel: 2. Reading the channel will return the radio network status, with the following meanings. 0 Correct operation, every unit is communicating correctly. 1 Some, but not all RFScada slave units are responding to radio signals from the RFScada master unit. 2 None of the RFScada slave units are responding to radio signals from the RFScada master unit. If the radio network status is 1 it is possible to find out which units are not operating correctly, refer to the RFScada individual network status. RFScada Individual Network Status. This returns the operational status of an individual RFScada unit. To access a units status set up a channel as Device Type: RFScada; Device Number: The units ID, 0 to 31; I/O Type: Special; Channel: 0. Reading the channel will return units radio network status. 0 means the unit is responding correctly, and 1 indicates that there is no response from the unit. Typically this status would only be read after an error was reported from reading the RFScada Radio Network Status, since it is much quicker to read a single summary status than poll each individually. RFScada Software Version. The software version installed in the RFScada master unit may be read. To access the RFScada software version set up a channel as Device Type: RFScada; Device Number: 0; I/O Type: Special; Channel: 3. Reading the channel will return the software version as a number, e.g. 24 means software version 2.4 Local and Remote Analog Inputs. Analog inputs from every RFScada unit in a system may be read using the A to D read function. To read an input set up a channel with Device Type: RFScada; Device Number: The units ID, 0 to 31; I/O Type: A to D; Channel: the units channel, 1 to 8. Reading the channel will return the analog input as a number from 0 to 1023, which corresponds to 0 - 20mA. Local and Remote Digital Inputs. Digital inputs from every RFScada unit in a system may be read using the Dig In read function. To read an input set up a channel with Device Type: RFScada; Device Number: The units ID, 0 to 31; I/O Type: Dig In; Channel: the units channel, 1 to 8. Reading the channel will return the digital input as a number, either 0 if the input is open circuit or 1 if the input is shorted.
17 Devices
335
Local and Remote Analog Outputs. Analog outputs on every RFScada unit in a system may be written to directly if the output was configured for the Modbus Only mode using the RFScada configuration program. Once configured the outputs can be directly written by using the D to A write function. Use Device Type: RFScada; Device Number: The units ID, 0 to 31; I/O Type: D to A; Channel: the units channel, 1 to 8. Write to the channel a value from 0 to 1023, which corresponds to 0 - 20mA. Alternately the outputs may be written to by overriding analog inputs that are then routed by the RFScada master unit to the desired analog output(s). Typically a non-existent virtual units analog input is over written, and this is then routed wherever it is desired. To do this set up a channel that will use the D to A write function. Use Device Type: RFScada; Device Number: The units ID, 0 to 31; I/O Type: D to A; Channel: the units channel, 1 to 8. Write to the channel a value from 0 to 1023, which corresponds to 0 - 20mA. Please refer to the RFScada manual for further details. Local and Remote Digital Outputs. Digital outputs on every RFScada unit in a system may be written to directly if the output was configured for the Modbus Only mode using the RFScada configuration program. Once configured the outputs can be directly written by using the Dig Out write function. To do this set up a channel that will use the Dig Out write function. Use Device Type: RFScada; Device Number: The units ID, 0 to 31; I/O Type: Dig Out; Channel: the units channel, 1 to 8. Write to the channel either a 1 (relay active, n.o. contacts closed) or 0 (relay inactive, n.o contacts open). Alternately the outputs may be written to by overriding digital inputs that are then routed by the RFScada master unit to the desired digital output(s). Typically a non-existent virtual units digital input is over written, and this is then routed wherever it is desired. To do this set up a channel that will use the Dig Out write function. Use Device Type: RFScada; Device Number: The units ID, 0 to 31; I/O Type: Dig Out; Channel: the units channel, 1 to 8. Write to the channel either a 1 (relay active, n.o. contacts closed) or 0 (relay inactive, n.o contacts open). Please refer to the RFScada manual for further details. Cautions when Writing to Outputs. The RFScada Units are designed for operation in many diverse applications, and may control devices such as motors and pumps. It is possible during operation that the PC could fail, it may lose power or the serial connection between the PC and the RFScada Unit is lost for some reason. If this occurs it is important that the RFScada sets all of its outputs to the default off state, (Analog outputs at 0 mA, all digital output relays off) to prevent any possible hazards or equipment damage. For this reason the RFScada Unit has a user programmable Modbus Override Time value that needs to be set appropriately for the application (the default is normally 10 seconds). If a Modbus write to overwritten registers does not occur within this time all overwritten registers on that unit will revert to the default state. So, in the DAQFactory application any output writes will need to be repeated by DAQFactory within the Modbus Override Time to prevent written values reverting to default values. Just writing to a single output, either analog or digital, on a unit will reset that units timeout and all overwritten values on that unit will remain without requiring any other writes, since the timeout is for the unit as a whole and not for individual registers. A simple DAQFactory Sequence that keeps writing more frequently than the Modbus override time to any register on any overwritten Unit will allow correct operation.
A to D: Reads the value of a sensor and returns the value in the appropriate engineering units. Sensor type
should be setup using the Set Sensor Type channel command.
Channel Commands:
This device has multiple Channel Commands to allow you access to all the features of the hardware. The first Command, Set Board Address, is required before any other actions can be performed with this driver.
Set Board Address: Identifies the SmartAD board in your system (since you could have multiples). The
17 Devices17.13 RFScada device
336
device number specified for this Channel Command will be used in all subsequent DAQFactory channels that reference this board. It should be a number between 0 and 15 inclusive and be unique among SmartAD boards if you have multiple boards in your system. This is identical to the SetBoardAttr() API function and has the following parameters, all of which must be specified:
Model Number: This is the model number of your board (i.e. "618") Address: This is the address of your board and differs depending on whether the board is on ISA bus, PCI bus,
or networked. In general, you should specify the I/O address (in decimal not hex) of the board if it is on an ISA bus, "0" (zero) for PCI bus which will automatically select the first board found, or the dot notation address for network boards (i.e. "10.0.0.1") Please see the Smart A/D docs for more information on this.
Reset Board: Invokes a soft reset of the specified (through the device number) SmartAD board. Set IO Net Timeout: Sets the timeout in milliseconds for networked I/O Set Hi Speed Mode: Sets the A to D into high speed mode. Only a reset board can reset this state. Use this
before declaring any sensor types.
Reject 50 hz: Rejects 50 hz noise. Only a resetboard can reset this state to 60 hz. Use this before declaring
sensor types.
Get Fault Flags: Returns the any fault flags. Unlike other channel commands that simply bounce back the
values sent, this command returns the value of the flags.
Check IO Net Reset: Returns non-zero if IONet unit has been reset since the last time this function was
called. Unlike other channel commands that simply bounce back the values sent, this command returns the value of the flags.
Set Fail Mode: Sets the failure mode for a data value. The Channels parameter specifies which channels to
apply this command to. This should be a comma delimited list of channel numbers or the word "Value" to use the set to value. The second parameter determines whether the system should fail high or fail low.
Set Filter: Sets the filter value for channels. The Channels parameter specifies which channels to apply this
command to. This should be a comma delimited list of channel numbers or the word "Value" to use the set to value. The second parameter determines the filter value and should range from 0 to 255, where 0 is no filtering and 255 is maximum filtering.
Set Sensor Type: Sets the type of sensor connect to a channel or channels. The Channels parameter specifies
which channels to apply this command to. This should be a comma delimited list of channel numbers or the word "Value" to use the set to value. Select the sensor type from the list, or select "Value" if you know the Logical Sensor Definition code and want to use the set value for the command.
Set Gage Zero, Set Gage Span, Set Gage Tare, Set Gage Cal: These commands are used for
gage type channels. See your hardware manual for the proper values. Like other commands that take channels, you can specify a comma delimited list to apply the command to multiple channels.
Get Ambient Temp: Returns the ambient temperature of a termination board. The termination board
parameter should be either 0 or 1.
17 Devices
337
that is placed on top of the spectrum is determined by the channel number. The output I/O types and String I/O type simply bounce back their set points. Because of this, you can use the output Channels of the Test device as a place to store variables or flags for use in sequences that need to be adjustable from a remote copy of DAQFactory. Simply create a Test device output channel and set its value like you would set a real D to A or Digital Out. The A to D channel also has a channel parameter that allows you to try high speed mode. To access the parameter, set up an A to D channel as you normally would, then go to the last column of the table (or what is normally the Quick Note field in the Channel view, just above the Notes). Click on the button to the right of this field. This will open a dialog window where you can select the Channel parameter and enter in the parameters. For the A to D channel, the Channel parameter sets the number of samples that will be generated. The driver will use the timing of the channel to spread these samples out. So, for example, if you specified 1000 samples and your timing was 1 second, you would get 1000 samples per second, each separated by a millisecond.
A to D: This will read the value of the given ADC channel (using the read variable interface command). Since the
interface does not provide a way to determine the bit depth of the A to D, the value returned will be in raw bits (i.e. 0 to 4095 for a 12 bit ADC). Use a conversion to convert this into more useful units.
D to A: This will set the value of the given DAC channel (using the set variable interface command). Just like the
A to D, you must provide the value in bit format (0 to 4095 for a 12 bit DAC). Again, use a conversion to make this easier.
Dig In / Dig Out: This will read or set the value of a register, whether it is an input, output, relay, timer
contact, or counter contact. Use the channel command to select the source / destination. The default is input for Dig In, and output for Dig Out. The channel number specified is the register number, not the PLC's channel block. The PLC typically addresses these registers in blocks of 8. This driver works around this for you so you only need to specify the bit number (starting with 1) desired. NOTE: Since the PLC groups its registers in banks of 8, the driver must read the current state of the bank of 8 registers, then set the appropriate bit during Dig Outs. If the PLC ladder program changes one of these registers between the time that the state is read and the time it is set then the ladder bit changed will be lost.
Counter: This will read the value of the high speed counter. Channel Commands:
The first two channel commands are used to set the communication parameters for the driver. The default is Com1 at 38400 baud. The other serial parameters are already set to match the PLC (i.e. 8,N,1) and cannot be changed.
Set Comm Port: Sets the Windows Com port to use to communicate with the PLC. Use "1" for Com1, "2" for
Com2 etc. Default is 1. This setting applies to all PLC's on your computer. Therefore, you can only communicate with one chain of PLC's. The device number of the Channel Command is ignored.
Set Comm Handle: Sets the comm port handle to use. This should be set to a Windows comm port handle.
This usually comes from the Modem driver and allows you to communicate with a TriLogi PLC over a modem connection. There are no parameters. Once you create the Channel Command, you should set the channel to the value of the handle. This must be the first thing you do with the driver.
338
Set Baud Rate: Sets the baud rate to communicate with the PLC. The default is 38400. The device number of
the Channel Command is ignored.
Send: This allows you to send a command to the PLC manually. Only the command string should be entered. The
driver will add the @, the ID, the FCS, and the terminator. It will also wait for a response. The value of the response is returned to the Channel command.
Set Device ID: This allows you to set the device ID of a PLC. Of course you have to know the current Device
ID so the driver knows where to send this command. After calling this command, you will have to use the new Device Number matching the ID to access the PLC. Typically you will only use this command to initially set the ID of a PLC.
Read and Set Commands: There is a whole series of read and set commands that allow you to read and set
various registers. These match up exactly with the interface commands and are pretty self explanatory. Just remember that all indexes are 1 based and all values set or returned should be in raw units.
Update Real Time Clock: Updates the clock from a battery backed MX-RTC if available. No parameters. Halt PLC: Halts the execution of the PLC ladder program after the current scan. Does not affect reading or
setting I/O from this driver.
Resume PLC: Resumes execution after a Halt PLC command. Set Comm Handle: This command takes a comm port handle and uses this handle instead of initializing the
serial port. You should use this command before doing anything else with the driver. The comm port handle should come from the Modem device of the connectivity pack.
XVIII
340
C1001
The channel name provided was not found: 1) Check your spelling, check for typos. 2) If you are not specifying the connection, make sure the default connection is correct.
C1002
The name provided was not found: Check your spelling, check for typos.
C1003
The objects you have edited are on a connection that has become disconnected. Since DAQFactory cannot communicate with the remote site, your changes cannot be saved yet. Check the remote system and cabling and retry. More info...
C1004
An error occurred while trying to set the value. This is a general catch all error for something unexpected and may be due to hardware failure or system instability. You should probably save your work just in case and proceed with caution.
C1005
The variable name specified was not found and the data cannot be retrieved. 1) Check your spelling, check for typos. 2) Did you mean Private. instead of Var.? Static. instead of Registry.? etc. More info...
341
C1006
A conversion was specified for a channel that does not exist. Most likely, the conversion was deleted without updating the channels to which it applied. Check your channels for deleted conversions. More info...
C1007
A problem occurred trying to connect to your email server. The error varies and is provided at the end of the message. Check your email server setting, and your internet connection. Also make sure your username and password are correct and that you've selected the correct authentication method. More info...
C1008
A problem occurred trying to send the email message. The response from the server is provided. The action to fix this error depends on the response, but typically is either related to the settings (username / password / authentication method) or a problem with the server. More info...
C1009
Most of the System. functions that display windows can only be called from the main application thread. The main application thread is the thread that the DAQFactory user interface runs in. Sequences started with Begin Sequence run in their own thread and cannot open any windows. Events for channels and PID loops also usually run in their own threads and cannot open windows. The only reliable place to call the System. functions that open windows is from the Quick Sequence action of a component. More info...
C1010
There was a problem trying to open the data source for ODBC data logging. The most common mistake is to provide the file name of your database for the data source and not the ODBC data source name defined in the Windows ODBC manager. More info...
C1011
A problem occurred trying to create the table for data logging in your ODBC database. The possible causes are database specific. The most common is that the database is opened exclusive in another application and DAQFactory cannot open it for modification.
C1012
A problem occurred trying to access the table for data logging in your ODBC database. The possible causes are database specific. The most common is that the database is opened exclusive in another application and DAQFactory cannot open it for modification.
C1013
An error occurred while trying to log. The exact error message is also provided. Common problems include trying to
342
log to a file that is open exclusively in another application, logging to a ODBC table that already exists with the wrong field names, or the disk being full.
C1014
An error occurred trying to start up the thread used for the PID loop. This is usually caused by lack of memory or resources and is a good sign that you are overdriving your system. Try running DAQFactory with fewer other applications running.
C1015
Most of the System. variables that affect the display of windows can only be called from the main application thread. The main application thread is the thread that the DAQFactory user interface runs in. Sequences started with Begin Sequence run in their own thread and cannot open any windows. Events for channels and PID loops also usually run in their own threads and cannot open windows. The only reliable place to call the System. variables that affect the display of windows is from the Quick Sequence action of a component. More info...
C1016
The System.MessageBox function requires one of the following types: Help, AbortRetryIgnore, OKCancel, RetryCancel,YesNo, or YesNoCancel These types are case sensitive. More info...
C1017
There was insufficient resources to display the message box. Try running DAQFactory with fewer other applications running.
C1018
Must be either NoLogin, AuthLogin, or LoginPlain The specified authentication type for the email server must be one of the three options listed. More info...
C1019
An internal error occurred that was caught by DAQFactory. Unfortunately, what the error was cannot be determined, but it must be something rare or another message would be displayed. You should save your work under a different file name just in case the file is corrupted and restart DAQFactory.
C1020
Alarm logging will not occur. There was a problem trying to open the data source for ODBC alarm logging. The most common mistake is to
343
provide the file name of your database for the data source and not the ODBC data source name defined in the Windows ODBC manager. More info...
C1021
A problem occurred trying to create the table for alarm logging in your ODBC database. The possible causes are database specific. The most common is that the database is opened exclusive in another application and DAQFactory cannot open it for modification.
C1022
A problem occurred trying to access the table for alarm logging in your ODBC database. The possible causes are database specific. The most common is that the database is opened exclusive in another application and DAQFactory cannot open it for modification.
C1023
An error occurred while trying to open the alarm log file. The exact error message is also provided. Common problems include trying to log to a file that is open exclusively in another application, logging to a ODBC table that already exists with the wrong field names, or the disk being full.
C1024
This is a generic error that occurs when DAQFactory is unable to broadcast a command over the network. This can be caused by network failure or by internal errors. If the message persists, check you network connection, then save and restart DAQFactory.
C1025
An error occurred in the thread that sends commands over the network. The thread will be restarted but this may fail. If you find that commands are not being received remotely, you should restart DAQFactory. You may want to consider restarting anywhere.
C1026
(does not affect proper running of DAQFactory, but may indicate a further problem) The heartbeat thread simply sends a small packet over the network so remote copies of DAQFactory can tell that the connection is still established. There was an error in the thread that runs the heartbeat and the heartbeat had to be stopped. Remote copies of DAQFactory will probably still receive data. This probably won't affect anything, but may be an indication of other problems, such as lack of memory, resources, or network problems.
C1027
The was a problem averaging channel data. Most likely this comes from an invalid data point, such as infinity that can't be averaged. Your data at this point in time is invalid. You should check you device and make sure it is working properly.
344
C1028
The license you have purchased only supports a single device driver at a time. Check your channel table and make sure the Device Type column lists only one device for all your channels.
C1029
The license you have purchased does not support the particular channel parameters you specified. Check your channel table.
C1030
There was a problem with a particular device driver file. Try downloading the latest version of the device driver and reinstalling.
C1031
The license you purchased only supports certain devices. At least one of your channels specifies a device that is not supported. Check your channel table and any sequences that may reference devices.
C1032
Device drivers are made up of two files, one with a .dll extension and one with a .dds. DAQFactory generates this error if you have different versions of these two files. This usually does not cause any problems, but if you find expected features missing you should download and install the device driver again.
C1033
This occurs in one of three situations: 1) You loaded a document from another computer that references devices that are not installed on this system. 2) The .dds file for the device driver exists, but the .dll file is missing. 3) Dependency .dll files are missing. This usually occurs when you install the DAQFactory device driver but have forgotten to install the manufacturers drivers. DAQFactory relies on these drivers and therefore requires them. We cannot distribute them with DAQFactory because of copyright issues as well as for version control.
C1034
With any out of memory error, you should try running DAQFactory with less applications running. You can also try lowering the resolution and/or color depth of your screen and restarting DAQFactory. Shortening your channel's history lengths will also free up memory.
C1035
Sequences typically run in their own thread. For some reason DAQFactory was unable to start a thread for a
345
sequence. This is typically caused by lack of memory or resources. Try running DAQFactory with fewer other applications running. You can also try lowering the resolution and/or color depth of your screen and restarting DAQFactory. Shortening your channel's history lengths will also free up memory.
C1036
This is a generic catch-all error for any error that may occur in a sequence that does not have its own error. This is most likely caused by problems with the device or device driver, but could be caused by lack of memory or resources.
C1037
Please save work under a different name and restart DAQFactory. If this error occurs, something very unusual occurred and rather than crashing, DAQFactory has caught the error and generated this message. You should save your work under a different name just in case there is file corruption and restart DAQFactory. Rebooting probably is not a bad idea either.
C1038
If you specify Timing parameters for your channels that are too small and your computer cannot keep up, DAQFactory will detect the backlog and reset. If this just occurs once, then there was probably just a temporary increase in CPU usage caused by starting another application or something similar. In this case you are near the limit, but not over it. If this recurs at a relatively constant interval then the device you are communicating with cannot maintain the data rate specified. For example, the LabJack U12 takes about 16ms to acquire a data point. If you specify a timing interval of 0.01 for a LabJack channel, you will receive this error every 10 seconds or so. You should adjust your Timing values accordingly.
C1039
An unknown error occurred while trying to access and subset channel data. Check your subsetting.
C1040
The channel that you have requested data from does not have any values yet. This typically occurs in sequences that start when the document loads and reference input channels. The sequence starts before data has been acquired on the referenced channels and the sequence throws this error. To fix this, try adding a little delay to the beginning of the sequence to ensure acquisition has time to start, or use the IsEmpty() function to check for valid data before actually trying to use it.
C1041
If this error occurs while loading a new document, or starting a new document then things may simply not have shut down properly. You may want to restart just in case, but this is probably not required. If this error occurs during normal operation of your document, then there is a memory issue with your system. Unfortunately your document is probably corrupted and you will have to revert to a saved document when you restart. This is an indication of a fundamental operating system problem.
346
C1042
Some sort of uncaught error occurred while trying to compile your sequence. This is probably an uncaught problem with the compiler. You should email [email protected] with a copy of the sequence you were trying to compile and will determine the problem rapidly.
C1043
In your sequence an extra endwhile was found without a matching while() statement.
C1044
In your sequence a while() was found without a matching endwhile.
C1045
In your sequence an extra endfor was found without a matching for()
C1046
In your sequence, a for() statement was found without a matching endfor
C1047
In your sequence, an endif was found without a matching if() statement.
C1048
In your sequence, an if() statement was found without a matching endif.
C1049
In switch / case constructs, you must list all your case statements first before listing the default.
C1050
In the switch construct, you can have many case statements, but you can only have one default statement.
C1051
An endcase statement was found without a matching switch statement.
347
C1052
In your sequence, a switch statement was found without a matching endcase.
C1053
In your sequence, an endcatch statement was found without a matching catch statement.
C1054
In your sequence a catch statement was found without a matching endcatch.
C1055
There was a problem with the formatting of a line in your sequence.
C1056
A statement or function was found without the expected open parenthesis. Function()
C1057
A comment ("//") was found in the middle of a parenthesis, subset, or array notation.
C1058
An open parenthesis was found without the matching close parenthesis.
C1059
An open quote was found without the matching close quotes.
C1060
Most statements require a certain number of paremeters.
C1061
An open bracket was found without the matching close bracket.
348
C1062
This error occurs when a line in a sequence starts with something other than a letter. All statements start with a letter as do all channels and functions, so with the exception of a comment, all sequence lines must start with a letter.
C1063
An expression was found after a function call.
C1064
An expression was found after the decrement operator: For example: MyChannel-- + 3 is invalid
C1065
An expression was found after the increment operator: For example: MyChannel++ * 3 is invalid
C1066
An operator was specified that doesn't exist. For example MyChannel ^* 3
C1067
The expression parser was called with an empty expression. An empty expression is valid in many places, but not in all places.
C1068
'Value' can only be used in conversion or graph trace expressions The term Value is a special term that is used in conversion where a channel should be substituted, or in graph trace expressions where the X value should be substituted. This error occurs when you try an use this term in other expressions.
C1069
You tried to subset an array with no values in it.
C1070
Some operators require one parameter, for example: MyChannel++. Others require two, for example: MyChannel + 3. This error occurs when the second parameter is missing: MyChannel +
349
C1071
The given function was provided more parameters than it needs.
C1072
This occurs when the number of open { do not match the number of close }.
C1073
Example: MyChannel[3+(2*3))]
C1074
For example: MyChannel[3,5}]
C1075
For example: MyChannel[3+(2*5]
C1076
Example: MyChannel[3,{3,2]
C1077
Example: Sin(MyChannel[0]])
C1078
For example: Sin({2,5}})
C1079
For example: Sin(MyChannel[0)
350
C1080
For example: Sin({2,5)
C1081
For example: Var.x = MyChannel[3]]
C1082
For example: Var.x = 3 + (2 * 3))
C1085
For example: Var.x = MyFunction + 2 * 3
C1086
The proper number of parameters was provided, but one of the parameters had an empty value.
C1087
In older releases of DAQFactory you could subset relative to the current time by specifying negative subset values. This feature has been removed. Instead, use SysTime()-x. So before if you had MyChannel[-2,-5], replace this with MyChannel[SysTime()-2,SysTime()-5]
C1088
There was an error while performing a mathematical function.
C1089
An error occurred that does not fit into any other category. Check the syntax.
C1090
The ShiftTime() function requires an array that has time values to shift.
C1091
The FormatDateTime() function requires a numeric date/time in seconds since 1970 which is the DAQFactory
351
C1092
You used the Remove() function on a string with nothing in it and therefore nothing to remove.
C1093
You cannot search an empty string.
C1094
Fill(Value, Array Size). The second parameter, which determines how many elements to create must be greater than 0.
C1095
For example you cannot Concat() an array with 5 rows and 10 columns to an array with 7 rows and 12 columns. The Concat() function combines arrays along the rows dimension. The total rows in each row can be different, but the column and depth count must be the same.
C1096
A generic error occurred while trying to calculate the temperature. Most likely an invalid voltage or CJC was provided.
C1097
Many functions require numbers. Most will take a string operator and convert it to a number if necessary. Other will generate this error instead.
C1098
This occurs when DAQFactory has an array with a different size from its reported size. If this persists, contact tech support with the actions taken.
C1099
The given operator or function does not exist.
352
C1100
AscA requires a valid string.
C1101
ChrA() requires an array of values
C1102
SortTime() sorts an array based on the time of each data point. This requires an array with time values.
C1103
The boxcar functions only work on numeric values. More info on Boxcar functions...
C1104
The boxcar functions only work on single dimensional arrays, or an array with multiple rows, but only one column and one depth. Use subsetting and the Transpose() function to boxcar other dimensions. More info on Boxcar functions...
C1105
More info on Boxcar functions...
C1106
This is an internal error. BoxcarMinMax is a function used to optimize graphing and should only be called when values have time associated.
C1107
More info on the Smooth() function...
C1108
The Smooth() function only works on single dimensional arrays, or an array with multiple rows, but only one column and one depth. Use subsetting and the Transpose() function to Smooth other dimensions. More info on the Smooth() function...
353
C1109
More info on the Smooth() function...
C1110
More info on Histogram()...
C1111
More info on Histogram()...
C1112
GetTime() returns an array with the time associated with a value.
C1113
More info on Percentile()...
C1114
More info on Percentile()...
C1115
More info on Percentile()...
C1116
More info on curve fitting...
C1117
An error occurred trying to perform the curve fit. More info on curve fitting...
C1118
By the vary nature of the binary logging format, you cannot use it to log string data. You should use ASCII or ODBC database to log string data instead. More info...
354
C1119
In Safe Mode, no acquisition, PID loops, logging or sequences will start. You must leave safe mode (File-Leave Safe Mode) before you can start any sequences, PID loops, or logging sets.
C1120
Logging will still continue. There was an error trying to create the logging header file. This is most likely because the file is read-only, is open in another application, or the disk is full. More info...
C1121
There was a generic error while performing the File.Move() function. More than likely the destination already exists, or the source file does not exist. More info...
C1122
A generic error occurred while trying to do a File.Copy() function. More than likely, the source file does not exist. More info...
C1123
There was a generic error trying to retrieve the disk space. Most likely you tried to retrieve the disk space on a removable disk that has been removed. More info...
C1124
More than likely the directory still has files in it. More info...
C1125
More than likely, the directory already exists. More info...
C1126
The logarithm of a value <= 0 does not exist and therefore is invalid.
C1127
To help avoid hanging your computer when you accidentally write an infinite loop, DAQFactory by default limits the maximum number of sequence steps that can be executed in a second. If this is exceeded, this error occurs. This feature can be adjusted or disabled from File-Preferences... More info...