├── .Zeugwerk
└── config.json
├── .github
└── workflows
│ └── documentation.yml
├── .gitignore
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── docs
├── docfx.json
├── images
│ └── TcLog_header.svg
├── index.md
├── metadata.json
├── toc.yml
└── userguide
│ ├── configuration.md
│ ├── customization.md
│ ├── getting_started.md
│ ├── installation.md
│ ├── license.md
│ ├── logging.md
│ ├── performance.md
│ └── toc.yml
├── src
├── TcLog.sln
├── TcLogProj
│ ├── TcLog.libcat.xml
│ ├── TcLog
│ │ ├── CONSTANTS.TcGVL
│ │ ├── Logger
│ │ │ ├── LogLevelToAdsLogMsgType.TcPOU
│ │ │ ├── TcLog.TcPOU
│ │ │ ├── TcLogCore.TcPOU
│ │ │ ├── TcLogTrig.TcPOU
│ │ │ ├── _DataTypes
│ │ │ │ ├── Error.TcDUT
│ │ │ │ ├── ErrorCodes.TcDUT
│ │ │ │ ├── LogLevels.TcDUT
│ │ │ │ ├── LoggingConfiguration.TcDUT
│ │ │ │ └── RollingIntervals.TcDUT
│ │ │ ├── _Interfaces
│ │ │ │ ├── ILog.TcIO
│ │ │ │ └── ILogCore.TcIO
│ │ │ └── _Tests
│ │ │ │ └── TestWrapper_NET.TcPOU
│ │ ├── StringBuilder
│ │ │ ├── StringBuilder.TcPOU
│ │ │ └── _Interfaces
│ │ │ │ ├── ILimitedStringBuilder.TcIO
│ │ │ │ └── IStringBuilder.TcIO
│ │ ├── TcLog.plcproj
│ │ ├── TcLog.plcproj.bak
│ │ └── Utils
│ │ │ ├── AnyToString.TcPOU
│ │ │ ├── DateTime.TcPOU
│ │ │ ├── DeleteOldFiles.TcPOU
│ │ │ ├── DynamicStringBuffer.TcPOU
│ │ │ ├── GenerateTimeData.TcPOU.bak
│ │ │ ├── GetFileAgeInSeconds.TcPOU
│ │ │ ├── _DataTypes
│ │ │ ├── DeleteFilesState.TcDUT
│ │ │ └── PersistToFileState.TcDUT
│ │ │ └── _Tests
│ │ │ ├── ConvertAnyToString_TEST.TcPOU
│ │ │ ├── DateTime_TEST.TcPOU
│ │ │ └── DynamicStringBuffer_TEST.TcPOU
│ ├── TcLogProj.tsproj
│ └── TcLogTEST
│ │ ├── PlcTask.TcTTO
│ │ ├── TESTS.TcPOU
│ │ └── TcLogTEST.plcproj
└── TcLogTest.NET
│ ├── PersistingToFileSystem.cs
│ ├── PlcFixture.cs
│ └── TcLogTest.NET.csproj
└── tools
└── release_library.ps1
/.Zeugwerk/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "fileversion": 1,
3 | "solution": "src/TcLog.sln",
4 | "projects": [
5 | {
6 | "name": "TcLogProj",
7 | "plcs": [
8 | {
9 | "version": "0.2.2",
10 | "name": "TcLog",
11 | "type": "Library",
12 | "frameworks": {},
13 | "references": {
14 | "*": [
15 | "Tc2_Standard=*",
16 | "Tc2_System=*",
17 | "Tc2_Utilities=*",
18 | "Tc3_DynamicMemory=*",
19 | "Tc3_Modules=*",
20 | "Base Interfaces=newest"
21 | ]
22 | },
23 | "repositories": [],
24 | "bindings": {},
25 | "patches": {
26 | "platform": {},
27 | "argument": {}
28 | }
29 | }
30 | ]
31 | }
32 | ]
33 | }
34 |
--------------------------------------------------------------------------------
/.github/workflows/documentation.yml:
--------------------------------------------------------------------------------
1 | name: Documentation
2 | on:
3 | push:
4 | branches:
5 | - main
6 | paths:
7 | - 'docs/**'
8 | - 'src/**'
9 | pull_request:
10 | workflow_dispatch:
11 | jobs:
12 | Build:
13 | name: Documentation
14 | runs-on: ubuntu-latest
15 | steps:
16 | - name: Build
17 | uses: Zeugwerk/zkdoc-action@1.0.0
18 | with:
19 | username: ${{ secrets.ACTIONS_ZGWK_USERNAME }}
20 | password: ${{ secrets.ACTIONS_ZGWK_PASSWORD }}
21 | filepath: "."
22 | doc-folder: "docs"
23 | - name: Deploy
24 | uses: peaceiris/actions-gh-pages@v3
25 | with:
26 | deploy_key: ${{ secrets.ACTIONS_DEPLOY_KEY }}
27 | publish_dir: archive/docs/html
28 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # gitignore template for TwinCAT3
2 | # website: https://www.beckhoff.com/twincat3/
3 | #
4 | # Recommended: VisualStudio.gitignore
5 |
6 | # TwinCAT files
7 | *.tpy
8 | *.tclrs
9 | *.compiled-library
10 | *.compileinfo
11 | # Don't include the tmc-file rule if either of the following is true:
12 | # 1. You've got TwinCAT C++ projects, as the information in the TMC-file is created manually for the C++ projects (in that case, only (manually) ignore the tmc-files for the PLC projects)
13 | # 2. You've created a standalone PLC-project and added events to it, as these are stored in the TMC-file.
14 | *.tmc
15 | *.tmcRefac
16 | *.library
17 | *.project.~u
18 | *.tsproj.bak
19 | *.xti.bak
20 | *.~u
21 | .DS_Store
22 | LineIDs.dbg
23 | LineIDs.dbg.bak
24 | _Boot/
25 | _CompileInfo/
26 | _Libraries/
27 | _ModuleInstall/
28 |
29 |
30 | ## Ignore Visual Studio temporary files, build results, and
31 | ## files generated by popular Visual Studio add-ons.
32 | ##
33 | ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
34 |
35 | # User-specific files
36 | *.rsuser
37 | *.suo
38 | *.user
39 | *.userosscache
40 | *.sln.docstates
41 |
42 | # User-specific files (MonoDevelop/Xamarin Studio)
43 | *.userprefs
44 |
45 | # Mono auto generated files
46 | mono_crash.*
47 |
48 | # Build results
49 | [Dd]ebug/
50 | [Dd]ebugPublic/
51 | [Rr]elease/
52 | [Rr]eleases/
53 | x64/
54 | x86/
55 | [Ww][Ii][Nn]32/
56 | [Aa][Rr][Mm]/
57 | [Aa][Rr][Mm]64/
58 | bld/
59 | [Bb]in/
60 | [Oo]bj/
61 | [Ll]og/
62 | [Ll]ogs/
63 |
64 | # Visual Studio 2015/2017 cache/options directory
65 | .vs/
66 | # Uncomment if you have tasks that create the project's static files in wwwroot
67 | #wwwroot/
68 |
69 | # Visual Studio 2017 auto generated files
70 | Generated\ Files/
71 |
72 | # MSTest test Results
73 | [Tt]est[Rr]esult*/
74 | [Bb]uild[Ll]og.*
75 |
76 | # NUnit
77 | *.VisualState.xml
78 | TestResult.xml
79 | nunit-*.xml
80 |
81 | # Build Results of an ATL Project
82 | [Dd]ebugPS/
83 | [Rr]eleasePS/
84 | dlldata.c
85 |
86 | # Benchmark Results
87 | BenchmarkDotNet.Artifacts/
88 |
89 | # .NET
90 | project.lock.json
91 | project.fragment.lock.json
92 | artifacts/
93 |
94 | # Tye
95 | .tye/
96 |
97 | # ASP.NET Scaffolding
98 | ScaffoldingReadMe.txt
99 |
100 | # StyleCop
101 | StyleCopReport.xml
102 |
103 | # Files built by Visual Studio
104 | *_i.c
105 | *_p.c
106 | *_h.h
107 | *.ilk
108 | *.meta
109 | *.obj
110 | *.iobj
111 | *.pch
112 | *.pdb
113 | *.ipdb
114 | *.pgc
115 | *.pgd
116 | *.rsp
117 | *.sbr
118 | *.tlb
119 | *.tli
120 | *.tlh
121 | *.tmp
122 | *.tmp_proj
123 | *_wpftmp.csproj
124 | *.log
125 | *.tlog
126 | *.vspscc
127 | *.vssscc
128 | .builds
129 | *.pidb
130 | *.svclog
131 | *.scc
132 |
133 | # Chutzpah Test files
134 | _Chutzpah*
135 |
136 | # Visual C++ cache files
137 | ipch/
138 | *.aps
139 | *.ncb
140 | *.opendb
141 | *.opensdf
142 | *.sdf
143 | *.cachefile
144 | *.VC.db
145 | *.VC.VC.opendb
146 |
147 | # Visual Studio profiler
148 | *.psess
149 | *.vsp
150 | *.vspx
151 | *.sap
152 |
153 | # Visual Studio Trace Files
154 | *.e2e
155 |
156 | # TFS 2012 Local Workspace
157 | $tf/
158 |
159 | # Guidance Automation Toolkit
160 | *.gpState
161 |
162 | # ReSharper is a .NET coding add-in
163 | _ReSharper*/
164 | *.[Rr]e[Ss]harper
165 | *.DotSettings.user
166 |
167 | # TeamCity is a build add-in
168 | _TeamCity*
169 |
170 | # DotCover is a Code Coverage Tool
171 | *.dotCover
172 |
173 | # AxoCover is a Code Coverage Tool
174 | .axoCover/*
175 | !.axoCover/settings.json
176 |
177 | # Coverlet is a free, cross platform Code Coverage Tool
178 | coverage*.json
179 | coverage*.xml
180 | coverage*.info
181 |
182 | # Visual Studio code coverage results
183 | *.coverage
184 | *.coveragexml
185 |
186 | # NCrunch
187 | _NCrunch_*
188 | .*crunch*.local.xml
189 | nCrunchTemp_*
190 |
191 | # MightyMoose
192 | *.mm.*
193 | AutoTest.Net/
194 |
195 | # Web workbench (sass)
196 | .sass-cache/
197 |
198 | # Installshield output folder
199 | [Ee]xpress/
200 |
201 | # DocProject is a documentation generator add-in
202 | DocProject/buildhelp/
203 | DocProject/Help/*.HxT
204 | DocProject/Help/*.HxC
205 | DocProject/Help/*.hhc
206 | DocProject/Help/*.hhk
207 | DocProject/Help/*.hhp
208 | DocProject/Help/Html2
209 | DocProject/Help/html
210 |
211 | # Click-Once directory
212 | publish/
213 |
214 | # Publish Web Output
215 | *.[Pp]ublish.xml
216 | *.azurePubxml
217 | # Note: Comment the next line if you want to checkin your web deploy settings,
218 | # but database connection strings (with potential passwords) will be unencrypted
219 | *.pubxml
220 | *.publishproj
221 |
222 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
223 | # checkin your Azure Web App publish settings, but sensitive information contained
224 | # in these scripts will be unencrypted
225 | PublishScripts/
226 |
227 | # NuGet Packages
228 | *.nupkg
229 | # NuGet Symbol Packages
230 | *.snupkg
231 | # The packages folder can be ignored because of Package Restore
232 | **/[Pp]ackages/*
233 | # except build/, which is used as an MSBuild target.
234 | !**/[Pp]ackages/build/
235 | # Uncomment if necessary however generally it will be regenerated when needed
236 | #!**/[Pp]ackages/repositories.config
237 | # NuGet v3's project.json files produces more ignorable files
238 | *.nuget.props
239 | *.nuget.targets
240 |
241 | # Microsoft Azure Build Output
242 | csx/
243 | *.build.csdef
244 |
245 | # Microsoft Azure Emulator
246 | ecf/
247 | rcf/
248 |
249 | # Windows Store app package directories and files
250 | AppPackages/
251 | BundleArtifacts/
252 | Package.StoreAssociation.xml
253 | _pkginfo.txt
254 | *.appx
255 | *.appxbundle
256 | *.appxupload
257 |
258 | # Visual Studio cache files
259 | # files ending in .cache can be ignored
260 | *.[Cc]ache
261 | # but keep track of directories ending in .cache
262 | !?*.[Cc]ache/
263 |
264 | # Others
265 | ClientBin/
266 | ~$*
267 | *~
268 | *.dbmdl
269 | *.dbproj.schemaview
270 | *.jfm
271 | *.pfx
272 | *.publishsettings
273 | orleans.codegen.cs
274 |
275 | # Including strong name files can present a security risk
276 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
277 | #*.snk
278 |
279 | # Since there are multiple workflows, uncomment next line to ignore bower_components
280 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
281 | #bower_components/
282 |
283 | # RIA/Silverlight projects
284 | Generated_Code/
285 |
286 | # Backup & report files from converting an old project file
287 | # to a newer Visual Studio version. Backup files are not needed,
288 | # because we have git ;-)
289 | _UpgradeReport_Files/
290 | Backup*/
291 | UpgradeLog*.XML
292 | UpgradeLog*.htm
293 | ServiceFabricBackup/
294 | *.rptproj.bak
295 |
296 | # SQL Server files
297 | *.mdf
298 | *.ldf
299 | *.ndf
300 |
301 | # Business Intelligence projects
302 | *.rdl.data
303 | *.bim.layout
304 | *.bim_*.settings
305 | *.rptproj.rsuser
306 | *- [Bb]ackup.rdl
307 | *- [Bb]ackup ([0-9]).rdl
308 | *- [Bb]ackup ([0-9][0-9]).rdl
309 |
310 | # Microsoft Fakes
311 | FakesAssemblies/
312 |
313 | # GhostDoc plugin setting file
314 | *.GhostDoc.xml
315 |
316 | # Node.js Tools for Visual Studio
317 | .ntvs_analysis.dat
318 | node_modules/
319 |
320 | # Visual Studio 6 build log
321 | *.plg
322 |
323 | # Visual Studio 6 workspace options file
324 | *.opt
325 |
326 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
327 | *.vbw
328 |
329 | # Visual Studio 6 auto-generated project file (contains which files were open etc.)
330 | *.vbp
331 |
332 | # Visual Studio 6 workspace and project file (working project files containing files to include in project)
333 | *.dsw
334 | *.dsp
335 |
336 | # Visual Studio 6 technical files
337 | *.ncb
338 | *.aps
339 |
340 | # Visual Studio LightSwitch build output
341 | **/*.HTMLClient/GeneratedArtifacts
342 | **/*.DesktopClient/GeneratedArtifacts
343 | **/*.DesktopClient/ModelManifest.xml
344 | **/*.Server/GeneratedArtifacts
345 | **/*.Server/ModelManifest.xml
346 | _Pvt_Extensions
347 |
348 | # Paket dependency manager
349 | .paket/paket.exe
350 | paket-files/
351 |
352 | # FAKE - F# Make
353 | .fake/
354 |
355 | # CodeRush personal settings
356 | .cr/personal
357 |
358 | # Python Tools for Visual Studio (PTVS)
359 | __pycache__/
360 | *.pyc
361 |
362 | # Cake - Uncomment if you are using it
363 | # tools/**
364 | # !tools/packages.config
365 |
366 | # Tabs Studio
367 | *.tss
368 |
369 | # Telerik's JustMock configuration file
370 | *.jmconfig
371 |
372 | # BizTalk build output
373 | *.btp.cs
374 | *.btm.cs
375 | *.odx.cs
376 | *.xsd.cs
377 |
378 | # OpenCover UI analysis results
379 | OpenCover/
380 |
381 | # Azure Stream Analytics local run output
382 | ASALocalRun/
383 |
384 | # MSBuild Binary and Structured Log
385 | *.binlog
386 |
387 | # NVidia Nsight GPU debugger configuration file
388 | *.nvuser
389 |
390 | # MFractors (Xamarin productivity tool) working folder
391 | .mfractor/
392 |
393 | # Local History for Visual Studio
394 | .localhistory/
395 |
396 | # Visual Studio History (VSHistory) files
397 | .vshistory/
398 |
399 | # BeatPulse healthcheck temp database
400 | healthchecksdb
401 |
402 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
403 | MigrationBackup/
404 |
405 | # Ionide (cross platform F# VS Code tools) working folder
406 | .ionide/
407 |
408 | # Fody - auto-generated XML schema
409 | FodyWeavers.xsd
410 |
411 | # VS Code files for those working on multiple tools
412 | .vscode/*
413 | !.vscode/settings.json
414 | !.vscode/tasks.json
415 | !.vscode/launch.json
416 | !.vscode/extensions.json
417 | *.code-workspace
418 |
419 | # Local History for Visual Studio Code
420 | .history/
421 |
422 | # Windows Installer files from build outputs
423 | *.cab
424 | *.msi
425 | *.msix
426 | *.msm
427 | *.msp
428 |
429 | # JetBrains Rider
430 | *.sln.iml
431 |
432 | ##
433 | ## Visual studio for Mac
434 | ##
435 |
436 |
437 | # globs
438 | Makefile.in
439 | *.userprefs
440 | *.usertasks
441 | config.make
442 | config.status
443 | aclocal.m4
444 | install-sh
445 | autom4te.cache/
446 | *.tar.gz
447 | tarballs/
448 | test-results/
449 |
450 | # Mac bundle stuff
451 | *.dmg
452 | *.app
453 |
454 | # content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore
455 | # General
456 | .DS_Store
457 | .AppleDouble
458 | .LSOverride
459 |
460 | # Icon must end with two \r
461 | Icon
462 |
463 |
464 | # Thumbnails
465 | ._*
466 |
467 | # Files that might appear in the root of a volume
468 | .DocumentRevisions-V100
469 | .fseventsd
470 | .Spotlight-V100
471 | .TemporaryItems
472 | .Trashes
473 | .VolumeIcon.icns
474 | .com.apple.timemachine.donotpresent
475 |
476 | # Directories potentially created on remote AFP share
477 | .AppleDB
478 | .AppleDesktop
479 | Network Trash Folder
480 | Temporary Items
481 | .apdisk
482 |
483 | # content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore
484 | # Windows thumbnail cache files
485 | Thumbs.db
486 | ehthumbs.db
487 | ehthumbs_vista.db
488 |
489 | # Dump file
490 | *.stackdump
491 |
492 | # Folder config file
493 | [Dd]esktop.ini
494 |
495 | # Recycle Bin used on file shares
496 | $RECYCLE.BIN/
497 |
498 | # Windows Installer files
499 | *.cab
500 | *.msi
501 | *.msix
502 | *.msm
503 | *.msp
504 |
505 | # Windows shortcuts
506 | *.lnk
507 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | :blue_heart: :+1: Thanks for your time and effort in contributing to this project! :+1: :blue_heart:
2 |
3 | There are several ways to contribute to this project. You can report bugs, suggest enhancements or directly contribute code via pull requests.
4 |
5 | ### Reporting bugs
6 |
7 | * Please use the GitHub issue search feature to check if your bug is already reported.
8 | * If it is not reported yet, please provide a detailed description of the problem, including the steps to reproduce it.
9 | * If possible, please provide a minimalistic code example that reproduces the problem.
10 | * If possible, please provide screenshots that illustrate the problem.
11 |
12 | ### Suggesting enhancements
13 |
14 | * Please use the GitHub issue search feature to check if your enhancement is already suggested.
15 | * If it is not suggested yet, please provide a detailed description of your proposal, including the use case behind it.
16 | * If possible, please provide a minimalistic code example that illustrates your proposal.
17 |
18 | ### Pull requests
19 |
20 | Please make sure that your pull request
21 | * is based on the `main` branch
22 | * only contains related commits
23 | * contains a detailed description of the changes
24 | * contains tests for the changes
25 |
26 |
27 | ### Environment setup
28 |
29 | #### TwinCAT and Visual Studio
30 | The project uses TwinCAT 3.1.4024.29 and Visual Studio 2019 with .NET 7.0.
31 |
32 | Please use the recommended [Zeugwerk IDE settings.](https://doc.zeugwerk.dev/contribute/recom_xae_settings.html)
33 |
34 | #### Unit tests
35 |
36 | [TcUnit](https://tcunit.org/) is used for unit tests in plc project itself.
37 |
38 | These tests are complemented by [XUnit](https://xunit.net/) tests in the .NET project. These tests mainly cover the the file-system related actions, since these are way easier to implement in .NET than in TwinCAT.
39 |
40 | #### Code style
41 |
42 | The project uses the [TcBlack](https://github.com/Roald87/TcBlack) formatter for TwinCAT code. Please make sure to format your code accordingly before creating a pull request.
43 |
44 | #### Naming conventions
45 |
46 | This project uses [Zeugwerk naming conventions](https://doc.zeugwerk.dev/contribute/contribute_code.html#naming-conventions) for the TwinCAT code.
47 |
48 | Unfortunately, the Beckhoff PLC Static Analysis does not support checking custom naming conventions yet. Therefore, please make sure to check your code manually before creating a pull request.
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 bengeisler
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | *Logging in TwinCAT with the on-board means is limited to the output as ADS event. The TcLog library presented here enables flexible logging to the file system.*
4 |
5 | It's usage is as simple as this:
6 |
7 | Configure the core logger in your project:
8 |
9 | ```st
10 | VAR
11 | _coreLogger : TcLogLib.TcLogCore(bufferSize := 100 * (Tc2_System.MAX_STRING_LENGTH + TcLogLib.Constants.FifoOverhead));
12 | END_VAR
13 |
14 | _coreLogger
15 | .WriteToAds()
16 | .WriteToFile('c:\logs\', 'sensor_data.txt')
17 | .MinimumLevel(TcLogLib.LogLevels.Debug)
18 | .RunLogger();
19 | ```
20 |
21 | Then, maybe in a different POU, use `TcLog` to log messages:
22 |
23 | ```st
24 | VAR
25 | _logger: TcLogLib.TcLog;
26 | _myInt : INT := 10;
27 | _myVarInfo : __SYSTEM.VAR_INFO := __VARINFO(_myInt);
28 | END_VAR
29 |
30 | _logger
31 | .AppendString('Let´s log some values: ')
32 | .AppendAny(_myInt)
33 | .AppendString(' - or some symbols: ')
34 | .AppendVariable(_myVarInfo, _myInt)
35 | .Error('');
36 | ```
37 |
38 | This will log both messages to both the ADS output and the file system.
39 |
40 | 🚀 **Features** 🚀
41 |
42 | - Log to ADS output
43 | - Log to file system
44 | - Fluent interface for easy configuration and usage
45 | - Specification of minimum log level
46 | - Set rolling interval for log files
47 | - Delete old log files automatically
48 | - Dynamically expanding log buffer
49 | - Log messages with or without timestamp
50 | - Custom log message formatting
51 |
52 | 🧪 **Tests** 🧪
53 |
54 | The project contains both unit ([TcUnit](https://tcunit.org)) and integration tests ([xUnit](https://xunit.net)).
55 |
56 | ## Install TcLog
57 | See the [installation guide](https://bengeisler.github.io/TcLog/userguide/installation.html) for instructions on how to install TcLog.
58 |
59 | ## Getting started
60 | Get quickly up and running with TcLog: [Get Started](https://bengeisler.github.io/TcLog/userguide/getting_started.html)
61 |
62 | ## API reference
63 | Find the full API reference [here](https://bengeisler.github.io/TcLog/reference/TcLogLib/Constants.html).
64 |
65 | ## License
66 | The library is licensed under the [MIT License](LICENSE).
67 |
68 | ## Contributing
69 | Contributions are welcome. Please see the [contribution guide](CONTRIBUTING.md) for details.
70 |
71 | Create a library release by running `.\release_library.ps1 -version "major.minor.patch"` from the `tools` folder. This removes the dependency on `TcUnit` and sets the lib version.
72 |
73 | ## Further ways of logging in TwinCAT
74 | With [log4TC](https://mbc-engineering.github.io/log4TC/index.html) there is another logging option for TwinCAT. This enables structured logging, but an additional Windows service must be installed, which communicates with the PLC library. `TcLog` on the other hand comes as a pure PLC library.
75 | The code for log4TC has been published as open source on [GitHub](https://github.com/mbc-engineering/log4TC/releases).
76 |
77 | ## Disclaimer
78 | This project is not affiliated with Beckhoff Automation GmbH & Co. KG and was first published in 2021 at [my blog](https://benediktgeisler.de/en/blog/tclog/).
79 |
--------------------------------------------------------------------------------
/docs/docfx.json:
--------------------------------------------------------------------------------
1 | {
2 | "build": {
3 | "content": [
4 | {
5 | "files": [
6 | "userguide/*.md",
7 | "userguide/toc.yml",
8 | "reference/**/*.md",
9 | "reference/toc.yml",
10 | "reference/**/toc.yml",
11 | "toc.yml",
12 | "*.md"
13 | ]
14 | }
15 | ],
16 | "resource": [
17 | {
18 | "files": ["images/**"]
19 | }
20 | ],
21 | "dest": "html",
22 | "fileMetadataFiles": [],
23 | "template": [
24 | "statictoc", "template"
25 | ],
26 | "postProcessors": [],
27 | "markdownEngineName": "markdig",
28 | "noLangKeyword": false,
29 | "keepFileLink": false,
30 | "cleanupCacheHistory": false,
31 | "disableGitFeatures": false
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/docs/images/TcLog_header.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
46 |
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | # TcLog
2 | `TcLog` is a flexible logging framework for TwinCAT 3 that allows to log to both the ADS output and the file system. It is designed to be easy to use and to integrate into your project. It has no external dependencies and is available as library for TwinCAT 3.
3 |
4 | It features the following:
5 | - Log to ADS output
6 | - Log to file system
7 | - Fluent interface for easy configuration and usage
8 | - Specification of minimum log level
9 | - Set rolling interval for log files
10 | - Delete old log files automatically
11 | - Dynamically expanding log buffer
12 | - Log messages with or without timestamp
13 | - Custom log message formatting
14 |
15 | The library is fully unit- and integration-tested.
16 |
17 | ## Install TcLog
18 | See here how to install TcLog:
19 |
20 |
21 | ## Getting started
22 | Get quickly up and running with TcLog:
23 |
24 |
25 | ## Documentation
26 | Find the full API reference here:
27 |
28 |
29 | ## License
30 | The library is licensed under the [MIT License](../LICENSE).
--------------------------------------------------------------------------------
/docs/metadata.json:
--------------------------------------------------------------------------------
1 | {
2 | "_appTitle": "TcLog",
3 | "_appFooter": "(c) 2023 Ben Geisler - Documentation powered by Zeugwerk GmbH",
4 | "_disableContribution": false
5 | }
6 |
--------------------------------------------------------------------------------
/docs/toc.yml:
--------------------------------------------------------------------------------
1 | - name: User guide
2 | href: userguide/
3 | - name: API Reference
4 | href: reference/
5 |
--------------------------------------------------------------------------------
/docs/userguide/configuration.md:
--------------------------------------------------------------------------------
1 | # Configuration
2 | `TcLogCore` is used to build the logging configuration and to run the persistence mechanism.
3 |
4 | ## Message format
5 | The message format can be adapted with several methods of `TcLogCore` that are described in the following.
6 |
7 | ### Delimiter
8 | `TcLogCore` can be configured to use an arbitrary delimiter between the components of the log entry with `.SetDelimiter('|')`.
9 |
10 | ### Including the instance path in the log message
11 | TcLog offers with `.IncludeInstancePath()` the possibility to include the location where the message was triggered into the message text:
12 |
13 | ```st
14 | _coreLogger
15 | .WriteToAds()
16 | .IncludeInstancePath()
17 | .MinimumLevel(LogLevels.Warning)
18 | .RunLogger();
19 |
20 | _logger.Error('This is an error message.');
21 | ```
22 |
23 | 
24 |
25 | ## Log to ADS output
26 | When adding the method `.WriteToAds()` to `TcLogCore`, the log messages are sent to the ADS output:
27 |
28 | ```st
29 | _coreLogger
30 | .WriteToAds()
31 | .RunLogger();
32 | ```
33 |
34 | ## Log to file system
35 | TcLog brings the option to store logs in the file system in the form of text files. This option can be applied to `TcLogCore` via the method `.WriteToFile(path, filename)`:
36 |
37 | ```st
38 | _coreLogger
39 | .IncludeInstancePath()
40 | .MinimumLevel(LogLevels.Warning)
41 | .WriteToFile('c:\logs\', 'test.txt')
42 | .RunLogger();
43 |
44 | _loggerTrig
45 | .OnRisingEdge(_log)
46 | .Error('rTrig Test');
47 | ```
48 |
49 | 
50 |
51 | ### Timestamp
52 | The file name is additionally prefixed with the creation date of the log file. The format of the date can be defined arbitrarily by means of a format string. Example:
53 |
54 | *YYMMDD-hh:mm:ss:iii*
55 |
56 | > [!IMPORTANT]
57 | > Upper and lower case must be maintained, furthermore the same letters must always be placed one after the other. Blocks of identical letters are not permitted: ~~*YYMMDD-YYYY*~~
58 |
59 | This format is passed to `TcLogCore` via the method `.TimestampFormat('YYMMDD-hh:mm:ss:iii')`.
60 |
61 | ## Minimum log level
62 | With the method `.MinimumLevel(level)` of `TcLogCore` the minimum log level can be specified. All messages with a lower log level are ignored.
63 |
64 | TcLog supports the following log levels:
65 | - `LogLevels.Debug`
66 | - `LogLevels.Information`
67 | - `LogLevels.Warning`
68 | - `LogLevels.Error`
69 | - `LogLevels.Fatal`
70 |
71 |
72 | ## Rolling interval
73 | A *rolling interval* denotes the interval until a new log file is created. TcLog offers the possibility to create a new logfile in regular intervals. This *rolling interval* is specified to `TcLogCore` via `SetRollingInterval(..)`:
74 | - `RollingIntervals.None`: Do not create a new log file.
75 | - `RollingIntervals.Hourly`: Create a new log file every hour
76 | - `RollingIntervals.Daily`: Create a new log file daily
77 | - `RollingIntervals.Monthly`: Create a new log file every month.
78 |
79 | The log file is only created when a message is triggered.
80 |
81 | ## Delete old log files
82 | To get rid of old log files, a lifespan of logs can be set with help of the method `DeleteLogsAfterDays(days)` of `TcLogCore`. Log files whose lifespan exceed the specified limit will automatically be deleted at midnight.
83 |
84 | ## Starting the logger
85 | After the configuration is complete, the logger is started with the method `RunLogger()` of `TcLogCore`.
86 |
87 | ## Using different verbosity levels
88 | Different scenarios may require different logging strategies. For example, you may want to log all messages with a log level of `Error` or higher in production, but all messages with a log level of `Debug` or higher in development. You can achieve this like this:
89 |
90 | ```st
91 | VAR
92 | _coreLogger : TcLogCore(bufferSize := 100 * (Tc2_System.MAX_STRING_LENGTH + Constants.FifoOverhead));
93 | _logger : TcLog;
94 | _isDevelopment : BOOL := TRUE;
95 | END_VAR
96 |
97 | _coreLogger
98 | .WriteToAds()
99 | .WriteToFile('c:\logs\', 'sensor_data.txt');
100 |
101 | IF _isDevelopment THEN
102 | _coreLogger.MinimumLevel(LogLevels.Debug);
103 | ELSE
104 | _coreLogger.MinimumLevel(LogLevels.Error);
105 | END_IF
106 |
107 | _coreLogger.RunLogger();
108 |
109 | _logger.Debug('This is a debug message.');
110 | _logger.Error('This is an error message.');
111 | ```
112 |
--------------------------------------------------------------------------------
/docs/userguide/customization.md:
--------------------------------------------------------------------------------
1 | # Customization
2 | TcLog is design to be easily customizable. This page shows how to customize the logger to your needs.
3 |
4 | ## Custom logging templates
5 | If one wants to record sensor data instead of the standard logs, for example, this is possible. The easiest way to do this is to program a wrapper around `TcLog` that enforces the specific template.
6 |
7 | ### Example: Logging of sensor data
8 |
9 | Suppose we want to record sensor data in `REAL` format. The data is to be saved in a csv file that has the following format:
10 |
11 | `hh:mm:ss;device designation;value;unit`
12 |
13 | And the output should look like this:
14 |
15 | `10:33:15;+CC1-B31;35.1;°C`
16 |
17 | ### Wrapper around `TcLog`
18 |
19 | As wrapper we use an function block that encapsulates `TcLog` and enforces the data input with the help of the inputs. Furthermore it implements the interface `ILog` which establishes the link between logger and base logger.
20 |
21 | ```st
22 | FUNCTION_BLOCK UserLog IMPLEMENTS ILog
23 | VAR_INPUT
24 | Condition: BOOL;
25 | Identification: STRING;
26 | Value: REAL;
27 | Unit: STRING;
28 | END_VAR
29 | VAR
30 | _getTimeData: DateTime;
31 | _timestamp: STRING;
32 | END_VAR
33 | VAR_STAT
34 | _logger: TcLog;
35 | END_VAR
36 |
37 | _getTimeData();
38 | _timestamp := _getTimeData.ToString('hh:mm:ss');
39 |
40 | _logger
41 | .OnCondition(Condition)
42 | .AppendString(_timestamp)
43 | .AppendString(';')
44 | .AppendString(Identification)
45 | .AppendString(';')
46 | .AppendAny(Value)
47 | .AppendString(';')
48 | .AppendString(Unit)
49 | .ToCustomFormat('');
50 | ```
51 |
52 | We can use the helper function `GenerateTimeData`, which returns the current date and time formatted via the `.ToString(Format)` method. With its help we generate the timestamp of the sensor data.
53 |
54 | The `.ToCustomFormat('')` method at the end of the chain causes the message to be logged unchanged. No additional information like further timestamps or instance path will be appended.
55 |
56 | ### The interface `ILog`
57 |
58 | The interface is implemented by passing the logger reference to the `TcLog` instance:
59 |
60 | ```st
61 | METHOD SetLogger : BOOL
62 | VAR_INPUT
63 | ref2Core : REFERENCE TO TcLogCore;
64 | END_VAR
65 |
66 | _logger.SetLogger(ref2Core);
67 | ```
68 |
69 | ### Calling the wrapper
70 |
71 | Somewhere in our program `TcLogCore` is called cyclically. If there is more than one instance of it, we can tell our logger which instance we want via `.SetLogger(Instance)`. Otherwise the configuration of the logger singleton is used.
72 |
73 | ```st
74 | VAR
75 | _newLogger: TcLogCore;
76 | _rTrigLog : R_TRIG;
77 | _log : BOOL;
78 | _myLog : UserLog;
79 | _myValue: REAL := 1.0;
80 | _myValue2: REAL := 2.0;
81 | END_VAR
82 |
83 | _newLogger
84 | .MinimumLevel(LogLevels.Information)
85 | .SetRollingInterval(RollingIntervals.Hourly)
86 | .WriteToFile('c:\logs\', 'sensor.csv')
87 | .DeleteLogFilesAfterDays(1)
88 | .RunLogger();
89 |
90 | _myLog.SetLogger(_newLogger);
91 | _rTrigLog(CLK := _log);
92 |
93 | _myLog(
94 | Condition := _rTrigLog.Q,
95 | Identification := '+CC1-B31',
96 | Value := _myValue,
97 | Unit := '°C');
98 |
99 | _myLog(
100 | Condition := _rTrigLog.Q,
101 | Identification := '+CC1-B32',
102 | Value := _myValue2,
103 | Unit := '°C');
104 | ```
105 |
106 | As soon as logging is triggered via `_log`, the csv file and the entries in it are created:
107 |
108 | 
109 |
110 | ## Use of custom loggers
111 | `TcLogCore` implements the `ILogCore` interface which defines the `LogCustomFormat` and `LogStandardFormat` methods.
112 | A custom logger with for example other log sinks can be created in two ways:
113 | 1. create a new FB that inherits from `TcLogCore`. Thereby the new FB can be extended by additional functions and at the same time brings along all methods that `TcLogCore` has.
114 | 2. create a new FB that implements the `ILogCore` interface. This way the logger can be rewritten from scratch. The interface ensures that the existing instances of `TcLog` in the code can still be used.
--------------------------------------------------------------------------------
/docs/userguide/getting_started.md:
--------------------------------------------------------------------------------
1 | # Getting started
2 | `TcLog` has two main building blocks:
3 | - `TcLog`, which is used to log messages.
4 | - `TcLogCore`, which is the central static logger that takes care of processing the logged messages, such as sending them to ADS ouput or persisting them to the file system.
5 |
6 | You would typically call `TcLogCore` once in your project and configure the logger behaviour. Then, you would use `TcLog` to log messages. Each call of `TcLog` then uses the same configuration specified with `TcLogCore`. While there is normally only one instance of `TcLogCore` in your project, you can create as many instances of `TcLog` as you like, typically one in each POU. Both `TcLog` and `TcLogCore` provide fluent interfaces to make configuration and log message creation as easy as possible.
7 |
8 | ## Example usage
9 | Configure the core logger in your project:
10 |
11 | ```st
12 | VAR
13 | _coreLogger : TcLogCore(bufferSize := 100 * (Tc2_System.MAX_STRING_LENGTH + Constants.FifoOverhead));
14 | END_VAR
15 |
16 | _coreLogger
17 | .WriteToAds()
18 | .WriteToFile('c:\logs\', 'sensor_data.txt')
19 | .MinimumLevel(LogLevels.Debug)
20 | .RunLogger();
21 | ```
22 |
23 | Then, maybe in a different POU, use `TcLog` to log messages:
24 |
25 | ```st
26 | VAR
27 | _logger : TcLog;
28 | END_VAR
29 |
30 | _logger.Debug('This is a debug message.');
31 | _logger.Error('This is an error message.');
32 | ```
33 |
34 | This will log both messages to both the ADS output and the file system.
35 |
36 | Next, see how to [configure TcLog](configuration.md) and how to [use TcLog in detail](logging.md).
--------------------------------------------------------------------------------
/docs/userguide/installation.md:
--------------------------------------------------------------------------------
1 | # Installation
2 | There are two ways to install this library:
3 | - download the latest release and install it manually or
4 | - install it via Twinpack.
5 |
6 | ## Manual Installation
7 |
8 | Download the latest release from [here](https://github.com/bengeisler/TcLog/releases/latest) and install it manually in your project. See the [Beckhoff documentation](https://infosys.beckhoff.com/english.php?content=../content/1033/tc3_plc_intro/4218300427.html&id=) on how to do this.
9 |
10 | ## Twinpack
11 | First, [install Twinpack](https://github.com/Zeugwerk/Twinpack#installation).
12 |
13 | Then, search for `TcLog` in the [Twinpack package manager](https://github.com/Zeugwerk/Twinpack#using-a-package) and install it.
14 |
15 |
16 |
--------------------------------------------------------------------------------
/docs/userguide/license.md:
--------------------------------------------------------------------------------
1 | # License
2 | MIT License
3 |
4 | Copyright (c) 2021 bengeisler
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
--------------------------------------------------------------------------------
/docs/userguide/logging.md:
--------------------------------------------------------------------------------
1 | # Logging
2 | Next, we will look at the logging options of TcLog.
3 |
4 | ## Flexible logging
5 | TcLog implements a [StringBuilder](https://www.plccoder.com/fluent-code/) which makes it easy to build your own message text:
6 |
7 | ```st
8 | VAR
9 | _logger: TcLog;
10 | _myInt : INT := 10;
11 | _myVarInfo : __SYSTEM.VAR_INFO := __VARINFO(_myInt);
12 | END_VAR
13 |
14 | _logger
15 | .AppendString('Let´s log some values: ')
16 | .AppendAny(_myInt)
17 | .AppendString(' - or some symbols: ')
18 | .AppendVariable(_myVarInfo, _myInt)
19 | .Error('');
20 | ```
21 | 
22 |
23 | Thus any amount of information can be appended to the message without having to implement `TcLog` with a large number of input parameters, since TwinCAT (at least in version before build 4026.0) does not allow optional input parameters.
24 |
25 | The methods `AppendString`, `AppendAny` and `AppendVariable` append the passed in data to the message text.
26 |
27 | The methods `Debug`, `Info`, `Warning`, `Error` and `Fatal` log the message with the respective log level. If you only want to log a simple string, you can pass it directly to the respective method, e.g. `_logger.Debug('This is a debug message.')`.
28 |
29 | ## Conditional logging
30 | The most common use of logging will be in the form `IF ... THEN log() END_IF`. Therefore this query is already integrated in TcLog:
31 |
32 | ```st
33 | VAR
34 | _logger: TcLog;
35 | _triggerLogging : R_TRIG;
36 | _log : BOOL;
37 | END_VAR
38 |
39 | _triggerLogging(CLK := _log);
40 | _logger
41 | .OnCondition(_triggerLogging.Q)
42 | .Error('Only logs when OnCondition evaluates to TRUE.');
43 | ```
44 |
45 | ## Logging on rising/falling edges
46 | Since a log message is usually to be sent once in the event of a *status change*, TcLog also provides a block for this purpose: `TcLogTrig`. In contrast to `TcLog`, a separate instance must be created for each use of this block, since the edge state is stored internally. The conditional execution can thus be further simplified:
47 |
48 | ```st
49 | VAR
50 | _loggerTrig : TcLogTRIG;
51 | _log : BOOL;
52 | END_VAR
53 |
54 | _loggerTrig
55 | .OnRisingEdge(_log)
56 | .Error('rTrig Test');
57 | ```
58 |
59 | Likewise, logging can be triggered on falling edges with `OnFallingEdge(cond)`.
60 |
61 | ## Use of multiple loggers
62 | Even though the logger was primarily designed as a singleton, it is possible to use multiple loggers. For example, sensor data can be collected cyclically and stored in a separate log file. To add another logger, an instance of `TcLogCore` must be created. This is then bound to the desired `TcLog` instance:
63 |
64 | ```st
65 | VAR
66 | _newLogger: TcLogCore(bufferSize := 100 * (Tc2_System.MAX_STRING_LENGTH + Constants.FifoOverhead));
67 | _logger: TcLog;
68 | _myInt : INT := 10;
69 | END_VAR
70 |
71 | _newLogger
72 | .MinimumLevel(LogLevels.Information)
73 | .SetRollingInterval(RollingIntervals.Hourly)
74 | .WriteToFile('c:\logs\', 'sensor_data.txt')
75 | .DeleteLogFilesAfterDays(7)
76 | .RunLogger();
77 |
78 | // Bind the new logger to the TcLog instance
79 | _logger.SetLogger(_newLogger);
80 |
81 | _logger.AppendString('Sensor xy: ')
82 | .AppendAny(_myInt)
83 | .Information('');
84 | ```
85 |
86 | From now on `_logger` considers the configuration of `_newLogger`.
87 |
88 | > **Note**: If you use multiple loggers, TcLog will always take the **first** initialized logger as default logger. Take this into account if you use multiple loggers.
--------------------------------------------------------------------------------
/docs/userguide/performance.md:
--------------------------------------------------------------------------------
1 | # Performance
2 | The logger can persist up to 100 messages per plc cycle. If you log more than that, the persistance mechanism will spread over several plc cycles. When logging less than 100 messages per cycle, it takes roughly `1.5 * # of consecutive cycles with logging` cycles to persist the messages; when logging more than 100 messages per cycle, multiply that value by a factor of 3.
--------------------------------------------------------------------------------
/docs/userguide/toc.yml:
--------------------------------------------------------------------------------
1 | - name: Installation
2 | href: installation.md
3 | - name: User guide
4 | items:
5 | - name: Getting started
6 | href: getting_started.md
7 | - name: Logging
8 | href: logging.md
9 | - name: Configuration
10 | href: configuration.md
11 | - name: Customization
12 | href: customization.md
13 | - name: License
14 | href: license.md
--------------------------------------------------------------------------------
/src/TcLog.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # TcXaeShell Solution File, Format Version 11.00
4 | VisualStudioVersion = 15.0.34829.251
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{B1E792BE-AA5F-4E3C-8C82-674BF9C0715B}") = "TcLogProj", "TcLogProj\TcLogProj.tsproj", "{84E2C694-C6B7-48C0-A46A-93E9E79E1E4B}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Debug|TwinCAT CE7 (ARMV7) = Debug|TwinCAT CE7 (ARMV7)
12 | Debug|TwinCAT OS (ARMT2) = Debug|TwinCAT OS (ARMT2)
13 | Debug|TwinCAT OS (ARMV7-A) = Debug|TwinCAT OS (ARMV7-A)
14 | Debug|TwinCAT OS (ARMV7-M) = Debug|TwinCAT OS (ARMV7-M)
15 | Debug|TwinCAT OS (ARMV8-A) = Debug|TwinCAT OS (ARMV8-A)
16 | Debug|TwinCAT OS (x64) = Debug|TwinCAT OS (x64)
17 | Debug|TwinCAT RT (x64) = Debug|TwinCAT RT (x64)
18 | Debug|TwinCAT RT (x86) = Debug|TwinCAT RT (x86)
19 | Release|Any CPU = Release|Any CPU
20 | Release|TwinCAT CE7 (ARMV7) = Release|TwinCAT CE7 (ARMV7)
21 | Release|TwinCAT OS (ARMT2) = Release|TwinCAT OS (ARMT2)
22 | Release|TwinCAT OS (ARMV7-A) = Release|TwinCAT OS (ARMV7-A)
23 | Release|TwinCAT OS (ARMV7-M) = Release|TwinCAT OS (ARMV7-M)
24 | Release|TwinCAT OS (ARMV8-A) = Release|TwinCAT OS (ARMV8-A)
25 | Release|TwinCAT OS (x64) = Release|TwinCAT OS (x64)
26 | Release|TwinCAT RT (x64) = Release|TwinCAT RT (x64)
27 | Release|TwinCAT RT (x86) = Release|TwinCAT RT (x86)
28 | EndGlobalSection
29 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
30 | {84E2C694-C6B7-48C0-A46A-93E9E79E1E4B}.Debug|Any CPU.ActiveCfg = Debug|TwinCAT RT (x64)
31 | {84E2C694-C6B7-48C0-A46A-93E9E79E1E4B}.Debug|Any CPU.Build.0 = Debug|TwinCAT RT (x64)
32 | {84E2C694-C6B7-48C0-A46A-93E9E79E1E4B}.Debug|TwinCAT CE7 (ARMV7).ActiveCfg = Debug|TwinCAT CE7 (ARMV7)
33 | {84E2C694-C6B7-48C0-A46A-93E9E79E1E4B}.Debug|TwinCAT CE7 (ARMV7).Build.0 = Debug|TwinCAT CE7 (ARMV7)
34 | {84E2C694-C6B7-48C0-A46A-93E9E79E1E4B}.Debug|TwinCAT OS (ARMT2).ActiveCfg = Debug|TwinCAT OS (ARMV8-A)
35 | {84E2C694-C6B7-48C0-A46A-93E9E79E1E4B}.Debug|TwinCAT OS (ARMV7-A).ActiveCfg = Debug|TwinCAT OS (ARMV7-A)
36 | {84E2C694-C6B7-48C0-A46A-93E9E79E1E4B}.Debug|TwinCAT OS (ARMV7-A).Build.0 = Debug|TwinCAT OS (ARMV7-A)
37 | {84E2C694-C6B7-48C0-A46A-93E9E79E1E4B}.Debug|TwinCAT OS (ARMV7-M).ActiveCfg = Debug|TwinCAT OS (ARMV7-M)
38 | {84E2C694-C6B7-48C0-A46A-93E9E79E1E4B}.Debug|TwinCAT OS (ARMV7-M).Build.0 = Debug|TwinCAT OS (ARMV7-M)
39 | {84E2C694-C6B7-48C0-A46A-93E9E79E1E4B}.Debug|TwinCAT OS (ARMV8-A).ActiveCfg = Debug|TwinCAT OS (ARMV8-A)
40 | {84E2C694-C6B7-48C0-A46A-93E9E79E1E4B}.Debug|TwinCAT OS (ARMV8-A).Build.0 = Debug|TwinCAT OS (ARMV8-A)
41 | {84E2C694-C6B7-48C0-A46A-93E9E79E1E4B}.Debug|TwinCAT OS (x64).ActiveCfg = Debug|TwinCAT OS (x64)
42 | {84E2C694-C6B7-48C0-A46A-93E9E79E1E4B}.Debug|TwinCAT OS (x64).Build.0 = Debug|TwinCAT OS (x64)
43 | {84E2C694-C6B7-48C0-A46A-93E9E79E1E4B}.Debug|TwinCAT RT (x64).ActiveCfg = Debug|TwinCAT RT (x64)
44 | {84E2C694-C6B7-48C0-A46A-93E9E79E1E4B}.Debug|TwinCAT RT (x64).Build.0 = Debug|TwinCAT RT (x64)
45 | {84E2C694-C6B7-48C0-A46A-93E9E79E1E4B}.Debug|TwinCAT RT (x86).ActiveCfg = Debug|TwinCAT RT (x86)
46 | {84E2C694-C6B7-48C0-A46A-93E9E79E1E4B}.Debug|TwinCAT RT (x86).Build.0 = Debug|TwinCAT RT (x86)
47 | {84E2C694-C6B7-48C0-A46A-93E9E79E1E4B}.Release|Any CPU.ActiveCfg = Release|TwinCAT RT (x64)
48 | {84E2C694-C6B7-48C0-A46A-93E9E79E1E4B}.Release|Any CPU.Build.0 = Release|TwinCAT RT (x64)
49 | {84E2C694-C6B7-48C0-A46A-93E9E79E1E4B}.Release|TwinCAT CE7 (ARMV7).ActiveCfg = Release|TwinCAT CE7 (ARMV7)
50 | {84E2C694-C6B7-48C0-A46A-93E9E79E1E4B}.Release|TwinCAT CE7 (ARMV7).Build.0 = Release|TwinCAT CE7 (ARMV7)
51 | {84E2C694-C6B7-48C0-A46A-93E9E79E1E4B}.Release|TwinCAT OS (ARMT2).ActiveCfg = Release|TwinCAT OS (ARMV8-A)
52 | {84E2C694-C6B7-48C0-A46A-93E9E79E1E4B}.Release|TwinCAT OS (ARMV7-A).ActiveCfg = Release|TwinCAT OS (ARMV7-A)
53 | {84E2C694-C6B7-48C0-A46A-93E9E79E1E4B}.Release|TwinCAT OS (ARMV7-A).Build.0 = Release|TwinCAT OS (ARMV7-A)
54 | {84E2C694-C6B7-48C0-A46A-93E9E79E1E4B}.Release|TwinCAT OS (ARMV7-M).ActiveCfg = Release|TwinCAT OS (ARMV7-M)
55 | {84E2C694-C6B7-48C0-A46A-93E9E79E1E4B}.Release|TwinCAT OS (ARMV7-M).Build.0 = Release|TwinCAT OS (ARMV7-M)
56 | {84E2C694-C6B7-48C0-A46A-93E9E79E1E4B}.Release|TwinCAT OS (ARMV8-A).ActiveCfg = Release|TwinCAT OS (ARMV8-A)
57 | {84E2C694-C6B7-48C0-A46A-93E9E79E1E4B}.Release|TwinCAT OS (ARMV8-A).Build.0 = Release|TwinCAT OS (ARMV8-A)
58 | {84E2C694-C6B7-48C0-A46A-93E9E79E1E4B}.Release|TwinCAT OS (x64).ActiveCfg = Release|TwinCAT OS (x64)
59 | {84E2C694-C6B7-48C0-A46A-93E9E79E1E4B}.Release|TwinCAT OS (x64).Build.0 = Release|TwinCAT OS (x64)
60 | {84E2C694-C6B7-48C0-A46A-93E9E79E1E4B}.Release|TwinCAT RT (x64).ActiveCfg = Release|TwinCAT RT (x64)
61 | {84E2C694-C6B7-48C0-A46A-93E9E79E1E4B}.Release|TwinCAT RT (x64).Build.0 = Release|TwinCAT RT (x64)
62 | {84E2C694-C6B7-48C0-A46A-93E9E79E1E4B}.Release|TwinCAT RT (x86).ActiveCfg = Release|TwinCAT RT (x86)
63 | {84E2C694-C6B7-48C0-A46A-93E9E79E1E4B}.Release|TwinCAT RT (x86).Build.0 = Release|TwinCAT RT (x86)
64 | {534B7BB3-9B49-4F2B-86CC-2317930EA23D}.Debug|Any CPU.ActiveCfg = Debug|TwinCAT RT (x64)
65 | {534B7BB3-9B49-4F2B-86CC-2317930EA23D}.Debug|Any CPU.Build.0 = Debug|TwinCAT RT (x64)
66 | {534B7BB3-9B49-4F2B-86CC-2317930EA23D}.Debug|TwinCAT CE7 (ARMV7).ActiveCfg = Debug|TwinCAT CE7 (ARMV7)
67 | {534B7BB3-9B49-4F2B-86CC-2317930EA23D}.Debug|TwinCAT CE7 (ARMV7).Build.0 = Debug|TwinCAT CE7 (ARMV7)
68 | {534B7BB3-9B49-4F2B-86CC-2317930EA23D}.Debug|TwinCAT OS (ARMT2).ActiveCfg = Debug|TwinCAT OS (ARMV8-A)
69 | {534B7BB3-9B49-4F2B-86CC-2317930EA23D}.Debug|TwinCAT OS (ARMV7-A).ActiveCfg = Debug|TwinCAT OS (ARMV7-A)
70 | {534B7BB3-9B49-4F2B-86CC-2317930EA23D}.Debug|TwinCAT OS (ARMV7-A).Build.0 = Debug|TwinCAT OS (ARMV7-A)
71 | {534B7BB3-9B49-4F2B-86CC-2317930EA23D}.Debug|TwinCAT OS (ARMV7-M).ActiveCfg = Debug|TwinCAT OS (ARMV7-M)
72 | {534B7BB3-9B49-4F2B-86CC-2317930EA23D}.Debug|TwinCAT OS (ARMV7-M).Build.0 = Debug|TwinCAT OS (ARMV7-M)
73 | {534B7BB3-9B49-4F2B-86CC-2317930EA23D}.Debug|TwinCAT OS (ARMV8-A).ActiveCfg = Debug|TwinCAT OS (ARMV8-A)
74 | {534B7BB3-9B49-4F2B-86CC-2317930EA23D}.Debug|TwinCAT OS (ARMV8-A).Build.0 = Debug|TwinCAT OS (ARMV8-A)
75 | {534B7BB3-9B49-4F2B-86CC-2317930EA23D}.Debug|TwinCAT OS (x64).ActiveCfg = Debug|TwinCAT OS (x64)
76 | {534B7BB3-9B49-4F2B-86CC-2317930EA23D}.Debug|TwinCAT OS (x64).Build.0 = Debug|TwinCAT OS (x64)
77 | {534B7BB3-9B49-4F2B-86CC-2317930EA23D}.Debug|TwinCAT RT (x64).ActiveCfg = Debug|TwinCAT RT (x64)
78 | {534B7BB3-9B49-4F2B-86CC-2317930EA23D}.Debug|TwinCAT RT (x64).Build.0 = Debug|TwinCAT RT (x64)
79 | {534B7BB3-9B49-4F2B-86CC-2317930EA23D}.Debug|TwinCAT RT (x86).ActiveCfg = Debug|TwinCAT RT (x86)
80 | {534B7BB3-9B49-4F2B-86CC-2317930EA23D}.Debug|TwinCAT RT (x86).Build.0 = Debug|TwinCAT RT (x86)
81 | {534B7BB3-9B49-4F2B-86CC-2317930EA23D}.Release|Any CPU.ActiveCfg = Release|TwinCAT RT (x64)
82 | {534B7BB3-9B49-4F2B-86CC-2317930EA23D}.Release|Any CPU.Build.0 = Release|TwinCAT RT (x64)
83 | {534B7BB3-9B49-4F2B-86CC-2317930EA23D}.Release|TwinCAT CE7 (ARMV7).ActiveCfg = Release|TwinCAT CE7 (ARMV7)
84 | {534B7BB3-9B49-4F2B-86CC-2317930EA23D}.Release|TwinCAT CE7 (ARMV7).Build.0 = Release|TwinCAT CE7 (ARMV7)
85 | {534B7BB3-9B49-4F2B-86CC-2317930EA23D}.Release|TwinCAT OS (ARMT2).ActiveCfg = Release|TwinCAT OS (ARMV8-A)
86 | {534B7BB3-9B49-4F2B-86CC-2317930EA23D}.Release|TwinCAT OS (ARMV7-A).ActiveCfg = Release|TwinCAT OS (ARMV7-A)
87 | {534B7BB3-9B49-4F2B-86CC-2317930EA23D}.Release|TwinCAT OS (ARMV7-A).Build.0 = Release|TwinCAT OS (ARMV7-A)
88 | {534B7BB3-9B49-4F2B-86CC-2317930EA23D}.Release|TwinCAT OS (ARMV7-M).ActiveCfg = Release|TwinCAT OS (ARMV7-M)
89 | {534B7BB3-9B49-4F2B-86CC-2317930EA23D}.Release|TwinCAT OS (ARMV7-M).Build.0 = Release|TwinCAT OS (ARMV7-M)
90 | {534B7BB3-9B49-4F2B-86CC-2317930EA23D}.Release|TwinCAT OS (ARMV8-A).ActiveCfg = Release|TwinCAT OS (ARMV8-A)
91 | {534B7BB3-9B49-4F2B-86CC-2317930EA23D}.Release|TwinCAT OS (ARMV8-A).Build.0 = Release|TwinCAT OS (ARMV8-A)
92 | {534B7BB3-9B49-4F2B-86CC-2317930EA23D}.Release|TwinCAT OS (x64).ActiveCfg = Release|TwinCAT OS (x64)
93 | {534B7BB3-9B49-4F2B-86CC-2317930EA23D}.Release|TwinCAT OS (x64).Build.0 = Release|TwinCAT OS (x64)
94 | {534B7BB3-9B49-4F2B-86CC-2317930EA23D}.Release|TwinCAT RT (x64).ActiveCfg = Release|TwinCAT RT (x64)
95 | {534B7BB3-9B49-4F2B-86CC-2317930EA23D}.Release|TwinCAT RT (x64).Build.0 = Release|TwinCAT RT (x64)
96 | {534B7BB3-9B49-4F2B-86CC-2317930EA23D}.Release|TwinCAT RT (x86).ActiveCfg = Release|TwinCAT RT (x86)
97 | {534B7BB3-9B49-4F2B-86CC-2317930EA23D}.Release|TwinCAT RT (x86).Build.0 = Release|TwinCAT RT (x86)
98 | {39E514BF-8337-4E82-99CA-D7D99BEEE7FE}.Debug|Any CPU.ActiveCfg = Debug|TwinCAT RT (x86)
99 | {39E514BF-8337-4E82-99CA-D7D99BEEE7FE}.Debug|TwinCAT CE7 (ARMV7).ActiveCfg = Debug|TwinCAT CE7 (ARMV7)
100 | {39E514BF-8337-4E82-99CA-D7D99BEEE7FE}.Debug|TwinCAT CE7 (ARMV7).Build.0 = Debug|TwinCAT CE7 (ARMV7)
101 | {39E514BF-8337-4E82-99CA-D7D99BEEE7FE}.Debug|TwinCAT OS (ARMT2).ActiveCfg = Debug|TwinCAT OS (ARMV8-A)
102 | {39E514BF-8337-4E82-99CA-D7D99BEEE7FE}.Debug|TwinCAT OS (ARMV7-A).ActiveCfg = Debug|TwinCAT OS (ARMV7-A)
103 | {39E514BF-8337-4E82-99CA-D7D99BEEE7FE}.Debug|TwinCAT OS (ARMV7-A).Build.0 = Debug|TwinCAT OS (ARMV7-A)
104 | {39E514BF-8337-4E82-99CA-D7D99BEEE7FE}.Debug|TwinCAT OS (ARMV7-M).ActiveCfg = Debug|TwinCAT OS (ARMV7-M)
105 | {39E514BF-8337-4E82-99CA-D7D99BEEE7FE}.Debug|TwinCAT OS (ARMV7-M).Build.0 = Debug|TwinCAT OS (ARMV7-M)
106 | {39E514BF-8337-4E82-99CA-D7D99BEEE7FE}.Debug|TwinCAT OS (ARMV8-A).ActiveCfg = Debug|TwinCAT OS (ARMV8-A)
107 | {39E514BF-8337-4E82-99CA-D7D99BEEE7FE}.Debug|TwinCAT OS (ARMV8-A).Build.0 = Debug|TwinCAT OS (ARMV8-A)
108 | {39E514BF-8337-4E82-99CA-D7D99BEEE7FE}.Debug|TwinCAT OS (x64).ActiveCfg = Debug|TwinCAT OS (x64)
109 | {39E514BF-8337-4E82-99CA-D7D99BEEE7FE}.Debug|TwinCAT OS (x64).Build.0 = Debug|TwinCAT OS (x64)
110 | {39E514BF-8337-4E82-99CA-D7D99BEEE7FE}.Debug|TwinCAT RT (x64).ActiveCfg = Debug|TwinCAT RT (x64)
111 | {39E514BF-8337-4E82-99CA-D7D99BEEE7FE}.Debug|TwinCAT RT (x64).Build.0 = Debug|TwinCAT RT (x64)
112 | {39E514BF-8337-4E82-99CA-D7D99BEEE7FE}.Debug|TwinCAT RT (x86).ActiveCfg = Debug|TwinCAT RT (x86)
113 | {39E514BF-8337-4E82-99CA-D7D99BEEE7FE}.Debug|TwinCAT RT (x86).Build.0 = Debug|TwinCAT RT (x86)
114 | {39E514BF-8337-4E82-99CA-D7D99BEEE7FE}.Release|Any CPU.ActiveCfg = Release|TwinCAT RT (x86)
115 | {39E514BF-8337-4E82-99CA-D7D99BEEE7FE}.Release|TwinCAT CE7 (ARMV7).ActiveCfg = Release|TwinCAT CE7 (ARMV7)
116 | {39E514BF-8337-4E82-99CA-D7D99BEEE7FE}.Release|TwinCAT CE7 (ARMV7).Build.0 = Release|TwinCAT CE7 (ARMV7)
117 | {39E514BF-8337-4E82-99CA-D7D99BEEE7FE}.Release|TwinCAT OS (ARMT2).ActiveCfg = Release|TwinCAT OS (ARMV8-A)
118 | {39E514BF-8337-4E82-99CA-D7D99BEEE7FE}.Release|TwinCAT OS (ARMV7-A).ActiveCfg = Release|TwinCAT OS (ARMV7-A)
119 | {39E514BF-8337-4E82-99CA-D7D99BEEE7FE}.Release|TwinCAT OS (ARMV7-A).Build.0 = Release|TwinCAT OS (ARMV7-A)
120 | {39E514BF-8337-4E82-99CA-D7D99BEEE7FE}.Release|TwinCAT OS (ARMV7-M).ActiveCfg = Release|TwinCAT OS (ARMV7-M)
121 | {39E514BF-8337-4E82-99CA-D7D99BEEE7FE}.Release|TwinCAT OS (ARMV7-M).Build.0 = Release|TwinCAT OS (ARMV7-M)
122 | {39E514BF-8337-4E82-99CA-D7D99BEEE7FE}.Release|TwinCAT OS (ARMV8-A).ActiveCfg = Release|TwinCAT OS (ARMV8-A)
123 | {39E514BF-8337-4E82-99CA-D7D99BEEE7FE}.Release|TwinCAT OS (ARMV8-A).Build.0 = Release|TwinCAT OS (ARMV8-A)
124 | {39E514BF-8337-4E82-99CA-D7D99BEEE7FE}.Release|TwinCAT OS (x64).ActiveCfg = Release|TwinCAT OS (x64)
125 | {39E514BF-8337-4E82-99CA-D7D99BEEE7FE}.Release|TwinCAT OS (x64).Build.0 = Release|TwinCAT OS (x64)
126 | {39E514BF-8337-4E82-99CA-D7D99BEEE7FE}.Release|TwinCAT RT (x64).ActiveCfg = Release|TwinCAT RT (x64)
127 | {39E514BF-8337-4E82-99CA-D7D99BEEE7FE}.Release|TwinCAT RT (x64).Build.0 = Release|TwinCAT RT (x64)
128 | {39E514BF-8337-4E82-99CA-D7D99BEEE7FE}.Release|TwinCAT RT (x86).ActiveCfg = Release|TwinCAT RT (x86)
129 | {39E514BF-8337-4E82-99CA-D7D99BEEE7FE}.Release|TwinCAT RT (x86).Build.0 = Release|TwinCAT RT (x86)
130 | EndGlobalSection
131 | GlobalSection(SolutionProperties) = preSolution
132 | HideSolutionNode = FALSE
133 | EndGlobalSection
134 | GlobalSection(ExtensibilityGlobals) = postSolution
135 | SolutionGuid = {9AC818C4-6839-46EB-8C84-95820330651F}
136 | EndGlobalSection
137 | EndGlobal
138 |
--------------------------------------------------------------------------------
/src/TcLogProj/TcLog.libcat.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | a008f0f9-813d-4727-ad9c-d60bc9412b1d
5 | 1.0.0.0
6 | TcLog
7 |
8 |
--------------------------------------------------------------------------------
/src/TcLogProj/TcLog/CONSTANTS.TcGVL:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
--------------------------------------------------------------------------------
/src/TcLogProj/TcLog/Logger/LogLevelToAdsLogMsgType.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
14 |
15 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/src/TcLogProj/TcLog/Logger/TcLog.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
39 |
40 |
41 |
42 |
43 |
52 |
53 |
58 |
59 |
60 |
61 |
69 |
70 |
75 |
76 |
77 |
78 |
104 |
105 |
119 |
120 |
121 |
122 |
129 |
130 | InvalidLoggerReference THEN
133 | _usedLogger.LogStandardFormat(Tc2_Standard.CONCAT(_logData, message), ShortenInstancePath(_instancePath), LogLevels.Debug);
134 | ELSE
135 | Tc2_System.ADSLOGSTR(ADSLOG_MSGTYPE_LOG OR LogLevelToAdsLogMsgType(LogLevels.Error), 'usedLogger: No valid reference', '');
136 | END_IF
137 | END_IF
138 | _logDataInitialized := FALSE;]]>
139 |
140 |
141 |
142 |
149 |
150 | InvalidLoggerReference THEN
153 | _usedLogger.LogStandardFormat(Tc2_Standard.CONCAT(_logData, message), ShortenInstancePath(_instancePath), LogLevels.Error);
154 | ELSE
155 | Tc2_System.ADSLOGSTR(ADSLOG_MSGTYPE_LOG OR LogLevelToAdsLogMsgType(LogLevels.Error), 'usedLogger: No valid reference', '');
156 | END_IF
157 | END_IF
158 | _logDataInitialized := FALSE;
159 | ]]>
160 |
161 |
162 |
163 |
170 |
171 | InvalidLoggerReference THEN
174 | _usedLogger.LogStandardFormat(Tc2_Standard.CONCAT(_logData, message), ShortenInstancePath(_instancePath), LogLevels.Fatal);
175 | ELSE
176 | Tc2_System.ADSLOGSTR(ADSLOG_MSGTYPE_LOG OR LogLevelToAdsLogMsgType(LogLevels.Error), 'usedLogger: No valid reference', '');
177 | END_IF
178 | END_IF
179 | _logDataInitialized := FALSE;]]>
180 |
181 |
182 |
183 |
190 |
191 | InvalidLoggerReference THEN
194 | _usedLogger.LogStandardFormat(Tc2_Standard.CONCAT(_logData, message), ShortenInstancePath(_instancePath), LogLevels.Information);
195 | ELSE
196 | Tc2_System.ADSLOGSTR(ADSLOG_MSGTYPE_LOG OR LogLevelToAdsLogMsgType(LogLevels.Error), 'usedLogger: No valid reference', '');
197 | END_IF
198 | END_IF
199 | _logDataInitialized := FALSE;]]>
200 |
201 |
202 |
203 |
210 |
211 |
214 |
215 |
216 |
217 |
221 |
222 |
228 |
229 |
230 |
231 |
238 |
239 |
244 |
245 |
246 |
247 |
255 |
256 |
257 |
258 |
259 |
260 |
274 |
275 | 0) DO
279 | positionInString := Tc2_Standard.FIND(shortenedPath, '.');
280 | shortenedPath := Tc2_Standard.DELETE(shortenedPath, positionInString+1, 0);
281 | positionOfLastDot := positionOfLastDot+positionInString;
282 | END_WHILE
283 |
284 | shortenedPath := Path;
285 | // Delete instantiation of this FB (obvious information)
286 | shortenedPath := Tc2_Standard.DELETE(shortenedPath, Tc2_Standard.LEN(shortenedPath)-positionOfLastDot+1, positionOfLastDot);
287 | // Delete project information
288 | positionInString := Tc2_Standard.FIND(shortenedPath, '.');
289 | shortenedPath := Tc2_Standard.DELETE(shortenedPath, positionInString+1, 0);
290 | // Delete PLC information
291 | positionInString := Tc2_Standard.FIND(shortenedPath, '.');
292 | shortenedPath := Tc2_Standard.DELETE(shortenedPath, positionInString+1, 0);
293 |
294 | ShortenInstancePath := shortenedPath;]]>
295 |
296 |
297 |
298 |
305 |
306 |
313 |
314 |
315 |
316 |
324 |
325 | InvalidLoggerReference THEN
328 | _usedLogger.LogCustomFormat(Tc2_Standard.CONCAT(_logData, message));
329 | ELSE
330 | Tc2_System.ADSLOGSTR(ADSLOG_MSGTYPE_LOG OR LogLevelToAdsLogMsgType(LogLevels.Error), 'usedLogger: No valid reference', '');
331 | END_IF
332 | END_IF
333 | _logDataInitialized := FALSE;]]>
334 |
335 |
336 |
337 |
344 |
345 | InvalidLoggerReference THEN
348 | _usedLogger.LogStandardFormat(Tc2_Standard.CONCAT(_logData, message), ShortenInstancePath(_instancePath), LogLevels.Warning);
349 | ELSE
350 | Tc2_System.ADSLOGSTR(ADSLOG_MSGTYPE_LOG OR LogLevelToAdsLogMsgType(LogLevels.Error), 'usedLogger: No valid reference', '');
351 | END_IF
352 | END_IF
353 | _logDataInitialized := FALSE;]]>
354 |
355 |
356 |
357 |
--------------------------------------------------------------------------------
/src/TcLogProj/TcLog/Logger/TcLogTrig.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
11 |
12 |
13 |
24 |
25 |
30 |
31 |
32 |
33 |
44 |
45 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/src/TcLogProj/TcLog/Logger/_DataTypes/Error.TcDUT:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
16 |
17 |
--------------------------------------------------------------------------------
/src/TcLogProj/TcLog/Logger/_DataTypes/ErrorCodes.TcDUT:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
20 |
21 |
--------------------------------------------------------------------------------
/src/TcLogProj/TcLog/Logger/_DataTypes/LogLevels.TcDUT:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
18 |
19 |
--------------------------------------------------------------------------------
/src/TcLogProj/TcLog/Logger/_DataTypes/LoggingConfiguration.TcDUT:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
30 |
31 |
--------------------------------------------------------------------------------
/src/TcLogProj/TcLog/Logger/_DataTypes/RollingIntervals.TcDUT:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
18 |
--------------------------------------------------------------------------------
/src/TcLogProj/TcLog/Logger/_Interfaces/ILog.TcIO:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/TcLogProj/TcLog/Logger/_Interfaces/ILogCore.TcIO:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 |
14 |
15 |
16 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/src/TcLogProj/TcLog/Logger/_Tests/TestWrapper_NET.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
69 |
70 | = Number_of_log_cycles THEN
167 | _cycles := 0;
168 | Log_in_consecutive_cycles := FALSE;
169 | END_IF
170 | END_IF
171 |
172 | IF Log_multiple_logs_in_one_cycle THEN
173 | FOR _i:= 1 TO DINT_TO_INT(Number_of_logs_per_cycle) DO
174 | _logger.
175 | Error(Tc2_Standard.CONCAT('Logging multiple times per cycle. Current step: ', INT_TO_STRING(_i)));
176 | END_FOR
177 | Log_multiple_logs_in_one_cycle := FALSE;
178 | END_IF
179 |
180 | IF Log_multiple_logs_in_multiple_cycles THEN
181 | IF CycleCount <= Number_of_cycles THEN
182 | FOR _i:= 1 TO DINT_TO_INT(Number_of_logs_per_cycle) DO
183 | _logger
184 | .AppendString('Logging multiple times per cycle. Cycle: ')
185 | .AppendString(DINT_TO_STRING(CycleCount))
186 | .AppendString(' / Step: ')
187 | .AppendString(INT_TO_STRING(_i))
188 | .Error('');
189 | END_FOR
190 | CycleCount := CycleCount + 1;
191 | ELSE
192 | CycleCount := 1;
193 | Log_multiple_logs_in_multiple_cycles := FALSE;
194 | END_IF
195 | END_IF
196 |
197 | _persistenceTimeStaysWithinBounds(CLK := (Persistance_time_stays_within_bounds AND _coreLogger.Busy));
198 | IF _persistenceTimeStaysWithinBounds.Q THEN
199 | CycleCount := 1;
200 | Persistance_time_stays_within_bounds := FALSE;
201 | END_IF
202 | IF Persistance_time_stays_within_bounds THEN
203 | Duration_in_cylces := Duration_in_cylces + 1;
204 | IF CycleCount <= Number_of_cycles THEN
205 | FOR _i:= 1 TO DINT_TO_INT(Number_of_logs_per_cycle) DO
206 | _logger
207 | .AppendString('Logging multiple times per cycle. Cycle: ')
208 | .AppendString(DINT_TO_STRING(CycleCount))
209 | .AppendString(' / Step: ')
210 | .AppendString(INT_TO_STRING(_i))
211 | .Error('');
212 | END_FOR
213 | CycleCount := CycleCount + 1;
214 | END_IF
215 | END_IF
216 |
217 | // Check first cpu cycle
218 | _coreLoggerFirstCycle
219 | .IncludeInstancePath()
220 | .MinimumLevel(LogLevels.Warning)
221 | .SetDelimiter(Delimiter)
222 | .SetRollingInterval(RollingIntervals.Hourly)
223 | .DeleteLogFilesAfterDays(1)
224 | .TimestampFormat('_YYYYMMDD-hh-mm-ss_')
225 | .WriteToAds()
226 | .WriteToFile('C:\UnitTestFirstCycle\', 'firstCycle.txt')
227 | .RunLogger();
228 | _loggerFirstCycle.SetLogger(_coreLoggerFirstCycle);
229 |
230 | _coreLoggerFirstCycleValidTimestampOnly
231 | .IncludeInstancePath()
232 | .MinimumLevel(LogLevels.Warning)
233 | .SetDelimiter(Delimiter)
234 | .SetRollingInterval(RollingIntervals.Hourly)
235 | .DeleteLogFilesAfterDays(1)
236 | .TimestampFormat('_YYYYMMDD-hh-mm-ss_')
237 | .WriteToAds()
238 | .WriteToFile('C:\UnitTestFirstCycle\', 'firstCycleValidTimestampOnly.txt')
239 | .ValidTimestampsOnly()
240 | .RunLogger();
241 | _loggerFirstCycleValidTimestampOnly.SetLogger(_coreLoggerFirstCycleValidTimestampOnly);
242 |
243 | IF _isFirstCycle THEN
244 | _loggerFirstCycle.Error('Log in first cycle');
245 | _loggerFirstCycleValidTimestampOnly.Error('Log in first cycle');
246 | _isFirstCycle := FALSE;
247 | END_IF
248 |
249 |
250 | ]]>
251 |
252 |
253 |
--------------------------------------------------------------------------------
/src/TcLogProj/TcLog/StringBuilder/StringBuilder.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
13 |
14 |
19 |
20 |
22 |
23 |
24 |
25 |
31 |
32 |
36 |
37 |
38 |
39 |
45 |
46 |
48 |
49 |
50 |
51 |
62 |
63 |
73 |
74 |
75 |
76 |
78 |
79 |
81 |
82 |
83 |
84 |
86 |
87 |
88 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/src/TcLogProj/TcLog/StringBuilder/_Interfaces/ILimitedStringBuilder.TcIO:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 |
12 |
13 |
14 |
20 |
21 |
22 |
24 |
25 |
26 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/src/TcLogProj/TcLog/StringBuilder/_Interfaces/IStringBuilder.TcIO:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 |
12 |
13 |
14 |
20 |
21 |
22 |
28 |
29 |
30 |
37 |
38 |
39 |
41 |
42 |
43 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/src/TcLogProj/TcLog/TcLog.plcproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | 1.0.0.0
4 | 2.0
5 | {534b7bb3-9b49-4f2b-86cc-2317930ea23d}
6 | True
7 | true
8 | false
9 | false
10 | TcLog
11 | 3.1.4026.12
12 | {b17b6069-df5e-455f-9777-ca2592ee6113}
13 | {827c7b48-6b19-4663-8b59-fefb0b436024}
14 | {39cb5e76-4fe2-46f6-ae40-1fcb2a6531eb}
15 | {74ded4cd-273e-4f0f-8a1f-4c4d89389741}
16 | {d696fa89-a5b7-4359-9420-e6a3f2f66b93}
17 | {e556042a-b034-4e51-bfa4-92060eb4b7b8}
18 | Benedikt Geisler
19 | false
20 | TcLog
21 | 0.6.1
22 | false
23 | TcLogLib
24 | Benedikt Geisler
25 | TcLog provides logging functionality to TwinCAT.
26 |
27 |
28 | {a008f0f9-813d-4727-ad9c-d60bc9412b1d}
29 | 1.0.0.0
30 | TcLog
31 |
32 |
33 |
34 | {a008f0f9-813d-4727-ad9c-d60bc9412b1d}
35 |
36 | false
37 | false
38 | false
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | Code
54 | true
55 |
56 |
57 | Code
58 |
59 |
60 | Code
61 |
62 |
63 | Code
64 |
65 |
66 | Code
67 |
68 |
69 | Code
70 |
71 |
72 | Code
73 |
74 |
75 | Code
76 |
77 |
78 | Code
79 |
80 |
81 | Code
82 |
83 |
84 | Code
85 |
86 |
87 | Code
88 |
89 |
90 | Code
91 |
92 |
93 | Code
94 |
95 |
96 | Code
97 |
98 |
99 | Code
100 |
101 |
102 | Code
103 |
104 |
105 | Code
106 |
107 |
108 | Code
109 |
110 |
111 | Code
112 |
113 |
114 | Code
115 |
116 |
117 | Code
118 |
119 |
120 | Code
121 |
122 |
123 | Code
124 |
125 |
126 | Code
127 |
128 |
129 | Code
130 |
131 |
132 |
133 |
134 | IBaseLibrary
135 |
136 |
137 |
138 |
139 | Tc2_Standard, * (Beckhoff Automation GmbH)
140 | Tc2_Standard
141 |
142 |
143 | Tc2_System, * (Beckhoff Automation GmbH)
144 | Tc2_System
145 |
146 |
147 | Tc2_Utilities, * (Beckhoff Automation GmbH)
148 | Tc2_Utilities
149 |
150 |
151 | Tc3_DynamicMemory, * (Beckhoff Automation GmbH)
152 | Tc3_DynamicMemory
153 |
154 |
155 | Tc3_Module, * (Beckhoff Automation GmbH)
156 | Tc3_Module
157 |
158 |
159 | TcUnit, * (www.tcunit.org)
160 | TcUnit
161 |
162 |
163 |
164 |
165 | Content
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 | "<ProjectRoot>"
174 |
175 | {192FAD59-8248-4824-A8DE-9177C94C195A}
176 |
177 | "{192FAD59-8248-4824-A8DE-9177C94C195A}"
178 |
179 |
180 |
181 | {246001F4-279D-43AC-B241-948EB31120E1}
182 |
183 | "{246001F4-279D-43AC-B241-948EB31120E1}"
184 |
185 |
186 | GlobalVisuImageFilePath
187 | %APPLICATIONPATH%
188 |
189 |
190 | {29BD8D0C-3586-4548-BB48-497B9A01693F}
191 |
192 | "{29BD8D0C-3586-4548-BB48-497B9A01693F}"
193 |
194 | Rules
195 |
196 | "Rules"
197 |
198 |
199 |
200 |
201 |
202 |
203 | {40450F57-0AA3-4216-96F3-5444ECB29763}
204 |
205 | "{40450F57-0AA3-4216-96F3-5444ECB29763}"
206 |
207 |
208 | ActiveVisuProfile
209 | IR0whWr8bwfwBwAAiD2qpQAAAABVAgAA37x72QAAAAABAAAAAAAAAAEaUwB5AHMAdABlAG0ALgBTAHQAcgBpAG4AZwACTHsAZgA5ADUAYgBiADQAMgA2AC0ANQA1ADIANAAtADQAYgA0ADUALQA5ADQAMAAwAC0AZgBiADAAZgAyAGUANwA3AGUANQAxAGIAfQADCE4AYQBtAGUABDBUAHcAaQBuAEMAQQBUACAAMwAuADEAIABCAHUAaQBsAGQAIAA0ADAAMgA0AC4ANwAFFlAAcgBvAGYAaQBsAGUARABhAHQAYQAGTHsAMQA2AGUANQA1AGIANgAwAC0ANwAwADQAMwAtADQAYQA2ADMALQBiADYANQBiAC0ANgAxADQANwAxADMAOAA3ADgAZAA0ADIAfQAHEkwAaQBiAHIAYQByAGkAZQBzAAhMewAzAGIAZgBkADUANAA1ADkALQBiADAANwBmAC0ANABkADYAZQAtAGEAZQAxAGEALQBhADgAMwAzADUANgBhADUANQAxADQAMgB9AAlMewA5AGMAOQA1ADgAOQA2ADgALQAyAGMAOAA1AC0ANAAxAGIAYgAtADgAOAA3ADEALQA4ADkANQBmAGYAMQBmAGUAZABlADEAYQB9AAoOVgBlAHIAcwBpAG8AbgALBmkAbgB0AAwKVQBzAGEAZwBlAA0KVABpAHQAbABlAA4aVgBpAHMAdQBFAGwAZQBtAE0AZQB0AGUAcgAPDkMAbwBtAHAAYQBuAHkAEAxTAHkAcwB0AGUAbQARElYAaQBzAHUARQBsAGUAbQBzABIwVgBpAHMAdQBFAGwAZQBtAHMAUwBwAGUAYwBpAGEAbABDAG8AbgB0AHIAbwBsAHMAEyhWAGkAcwB1AEUAbABlAG0AcwBXAGkAbgBDAG8AbgB0AHIAbwBsAHMAFCRWAGkAcwB1AEUAbABlAG0AVABlAHgAdABFAGQAaQB0AG8AcgAVIlYAaQBzAHUATgBhAHQAaQB2AGUAQwBvAG4AdAByAG8AbAAWFHYAaQBzAHUAaQBuAHAAdQB0AHMAFwxzAHkAcwB0AGUAbQAYGFYAaQBzAHUARQBsAGUAbQBCAGEAcwBlABkmRABlAHYAUABsAGEAYwBlAGgAbwBsAGQAZQByAHMAVQBzAGUAZAAaCGIAbwBvAGwAGyJQAGwAdQBnAGkAbgBDAG8AbgBzAHQAcgBhAGkAbgB0AHMAHEx7ADQAMwBkADUAMgBiAGMAZQAtADkANAAyAGMALQA0ADQAZAA3AC0AOQBlADkANAAtADEAYgBmAGQAZgAzADEAMABlADYAMwBjAH0AHRxBAHQATABlAGEAcwB0AFYAZQByAHMAaQBvAG4AHhRQAGwAdQBnAGkAbgBHAHUAaQBkAB8WUwB5AHMAdABlAG0ALgBHAHUAaQBkACBIYQBmAGMAZAA1ADQANAA2AC0ANAA5ADEANAAtADQAZgBlADcALQBiAGIANwA4AC0AOQBiAGYAZgBlAGIANwAwAGYAZAAxADcAIRRVAHAAZABhAHQAZQBJAG4AZgBvACJMewBiADAAMwAzADYANgBhADgALQBiADUAYwAwAC0ANABiADkAYQAtAGEAMAAwAGUALQBlAGIAOAA2ADAAMQAxADEAMAA0AGMAMwB9ACMOVQBwAGQAYQB0AGUAcwAkTHsAMQA4ADYAOABmAGYAYwA5AC0AZQA0AGYAYwAtADQANQAzADIALQBhAGMAMAA2AC0AMQBlADMAOQBiAGIANQA1ADcAYgA2ADkAfQAlTHsAYQA1AGIAZAA0ADgAYwAzAC0AMABkADEANwAtADQAMQBiADUALQBiADEANgA0AC0ANQBmAGMANgBhAGQAMgBiADkANgBiADcAfQAmFk8AYgBqAGUAYwB0AHMAVAB5AHAAZQAnVFUAcABkAGEAdABlAEwAYQBuAGcAdQBhAGcAZQBNAG8AZABlAGwARgBvAHIAQwBvAG4AdgBlAHIAdABpAGIAbABlAEwAaQBiAHIAYQByAGkAZQBzACgQTABpAGIAVABpAHQAbABlACkUTABpAGIAQwBvAG0AcABhAG4AeQAqHlUAcABkAGEAdABlAFAAcgBvAHYAaQBkAGUAcgBzACs4UwB5AHMAdABlAG0ALgBDAG8AbABsAGUAYwB0AGkAbwBuAHMALgBIAGEAcwBoAHQAYQBiAGwAZQAsEnYAaQBzAHUAZQBsAGUAbQBzAC1INgBjAGIAMQBjAGQAZQAxAC0AZAA1AGQAYwAtADQAYQAzAGIALQA5ADAANQA0AC0AMgAxAGYAYQA3ADUANgBhADMAZgBhADQALihJAG4AdABlAHIAZgBhAGMAZQBWAGUAcgBzAGkAbwBuAEkAbgBmAG8AL0x7AGMANgAxADEAZQA0ADAAMAAtADcAZgBiADkALQA0AGMAMwA1AC0AYgA5AGEAYwAtADQAZQAzADEANABiADUAOQA5ADYANAAzAH0AMBhNAGEAagBvAHIAVgBlAHIAcwBpAG8AbgAxGE0AaQBuAG8AcgBWAGUAcgBzAGkAbwBuADIMTABlAGcAYQBjAHkAMzBMAGEAbgBnAHUAYQBnAGUATQBvAGQAZQBsAFYAZQByAHMAaQBvAG4ASQBuAGYAbwA0MEwAbwBhAGQATABpAGIAcgBhAHIAaQBlAHMASQBuAHQAbwBQAHIAbwBqAGUAYwB0ADUaQwBvAG0AcABhAHQAaQBiAGkAbABpAHQAeQDQAAIaA9ADAS0E0AUGGgfQBwgaAUUHCQjQAAkaBEUKCwQDAAAABQAAAA0AAAAAAAAA0AwLrQIAAADQDQEtDtAPAS0Q0AAJGgRFCgsEAwAAAAUAAAANAAAAKAAAANAMC60BAAAA0A0BLRHQDwEtENAACRoERQoLBAMAAAAFAAAADQAAAAAAAADQDAutAgAAANANAS0S0A8BLRDQAAkaBEUKCwQDAAAABQAAAA0AAAAUAAAA0AwLrQIAAADQDQEtE9APAS0Q0AAJGgRFCgsEAwAAAAUAAAANAAAAAAAAANAMC60CAAAA0A0BLRTQDwEtENAACRoERQoLBAMAAAAFAAAADQAAAAAAAADQDAutAgAAANANAS0V0A8BLRDQAAkaBEUKCwQDAAAABQAAAA0AAAAAAAAA0AwLrQIAAADQDQEtFtAPAS0X0AAJGgRFCgsEAwAAAAUAAAANAAAAKAAAANAMC60EAAAA0A0BLRjQDwEtENAZGq0BRRscAdAAHBoCRR0LBAMAAAAFAAAADQAAAAAAAADQHh8tINAhIhoCRSMkAtAAJRoFRQoLBAMAAAADAAAAAAAAAAoAAADQJgutAAAAANADAS0n0CgBLRHQKQEtENAAJRoFRQoLBAMAAAADAAAAAAAAAAoAAADQJgutAQAAANADAS0n0CgBLRHQKQEtEJoqKwFFAAEC0AABLSzQAAEtF9AAHy0t0C4vGgPQMAutAQAAANAxC60XAAAA0DIarQDQMy8aA9AwC60CAAAA0DELrQMAAADQMhqtANA0Gq0A0DUarQA=
210 |
211 |
212 | {8A0FB252-96EB-4DCC-A5B4-B4804D05E2D6}
213 |
214 | "{8A0FB252-96EB-4DCC-A5B4-B4804D05E2D6}"
215 |
216 |
217 | WriteLineIDs
218 | False
219 |
220 |
221 | {8F99A816-E488-41E4-9FA3-846536012284}
222 |
223 | "{8F99A816-E488-41E4-9FA3-846536012284}"
224 |
225 |
226 | DisabledWarningIds
227 | 5410
228 |
229 |
230 | {F66C7017-BDD8-4114-926C-81D6D687E35F}
231 |
232 | "{F66C7017-BDD8-4114-926C-81D6D687E35F}"
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 | System.Boolean
242 | System.Collections.Hashtable
243 | {54dd0eac-a6d8-46f2-8c27-2f43c7e49861}
244 | System.String
245 |
246 |
247 |
248 |
249 |
--------------------------------------------------------------------------------
/src/TcLogProj/TcLog/TcLog.plcproj.bak:
--------------------------------------------------------------------------------
1 |
2 |
3 | 1.0.0.0
4 | 2.0
5 | {534b7bb3-9b49-4f2b-86cc-2317930ea23d}
6 | True
7 | true
8 | false
9 | false
10 | TcLog
11 | 3.1.4023.0
12 | {b17b6069-df5e-455f-9777-ca2592ee6113}
13 | {827c7b48-6b19-4663-8b59-fefb0b436024}
14 | {39cb5e76-4fe2-46f6-ae40-1fcb2a6531eb}
15 | {74ded4cd-273e-4f0f-8a1f-4c4d89389741}
16 | {d696fa89-a5b7-4359-9420-e6a3f2f66b93}
17 | {e556042a-b034-4e51-bfa4-92060eb4b7b8}
18 | Benedikt Geisler
19 | false
20 | TcLog
21 | 0.2.2
22 | false
23 | TcLog
24 | Benedikt Geisler
25 | TcLog provides logging functionality to TwinCAT.
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | Code
40 | true
41 |
42 |
43 | Code
44 |
45 |
46 | Code
47 |
48 |
49 | Code
50 |
51 |
52 | Code
53 |
54 |
55 | Code
56 |
57 |
58 | Code
59 |
60 |
61 | Code
62 |
63 |
64 | Code
65 |
66 |
67 | Code
68 |
69 |
70 | Code
71 |
72 |
73 | Code
74 |
75 |
76 | Code
77 |
78 |
79 | Code
80 |
81 |
82 | Code
83 |
84 |
85 | Code
86 |
87 |
88 | Code
89 |
90 |
91 | Code
92 |
93 |
94 | Code
95 |
96 |
97 | Code
98 |
99 |
100 | Code
101 |
102 |
103 | Code
104 |
105 |
106 | Code
107 |
108 |
109 |
110 |
111 | IBaseLibrary
112 |
113 |
114 |
115 |
116 | Tc2_Standard, * (Beckhoff Automation GmbH)
117 | Tc2_Standard
118 |
119 |
120 | Tc2_System, * (Beckhoff Automation GmbH)
121 | Tc2_System
122 |
123 |
124 | Tc2_Utilities, * (Beckhoff Automation GmbH)
125 | Tc2_Utilities
126 |
127 |
128 | Tc3_DynamicMemory, * (Beckhoff Automation GmbH)
129 | Tc3_DynamicMemory
130 |
131 |
132 | Tc3_Module, * (Beckhoff Automation GmbH)
133 | Tc3_Module
134 |
135 |
136 |
137 |
138 | Content
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 | "<ProjectRoot>"
147 |
148 | {8F99A816-E488-41E4-9FA3-846536012284}
149 |
150 | "{8F99A816-E488-41E4-9FA3-846536012284}"
151 |
152 |
153 |
154 | {29BD8D0C-3586-4548-BB48-497B9A01693F}
155 |
156 | "{29BD8D0C-3586-4548-BB48-497B9A01693F}"
157 |
158 | Rules
159 |
160 | "Rules"
161 |
162 |
163 |
164 |
165 |
166 |
167 | {40450F57-0AA3-4216-96F3-5444ECB29763}
168 |
169 | "{40450F57-0AA3-4216-96F3-5444ECB29763}"
170 |
171 |
172 | ActiveVisuProfile
173 | IR0whWr8bwfwBwAAiD2qpQAAAABVAgAA37x72QAAAAABAAAAAAAAAAEaUwB5AHMAdABlAG0ALgBTAHQAcgBpAG4AZwACTHsAZgA5ADUAYgBiADQAMgA2AC0ANQA1ADIANAAtADQAYgA0ADUALQA5ADQAMAAwAC0AZgBiADAAZgAyAGUANwA3AGUANQAxAGIAfQADCE4AYQBtAGUABDBUAHcAaQBuAEMAQQBUACAAMwAuADEAIABCAHUAaQBsAGQAIAA0ADAAMgA0AC4ANwAFFlAAcgBvAGYAaQBsAGUARABhAHQAYQAGTHsAMQA2AGUANQA1AGIANgAwAC0ANwAwADQAMwAtADQAYQA2ADMALQBiADYANQBiAC0ANgAxADQANwAxADMAOAA3ADgAZAA0ADIAfQAHEkwAaQBiAHIAYQByAGkAZQBzAAhMewAzAGIAZgBkADUANAA1ADkALQBiADAANwBmAC0ANABkADYAZQAtAGEAZQAxAGEALQBhADgAMwAzADUANgBhADUANQAxADQAMgB9AAlMewA5AGMAOQA1ADgAOQA2ADgALQAyAGMAOAA1AC0ANAAxAGIAYgAtADgAOAA3ADEALQA4ADkANQBmAGYAMQBmAGUAZABlADEAYQB9AAoOVgBlAHIAcwBpAG8AbgALBmkAbgB0AAwKVQBzAGEAZwBlAA0KVABpAHQAbABlAA4aVgBpAHMAdQBFAGwAZQBtAE0AZQB0AGUAcgAPDkMAbwBtAHAAYQBuAHkAEAxTAHkAcwB0AGUAbQARElYAaQBzAHUARQBsAGUAbQBzABIwVgBpAHMAdQBFAGwAZQBtAHMAUwBwAGUAYwBpAGEAbABDAG8AbgB0AHIAbwBsAHMAEyhWAGkAcwB1AEUAbABlAG0AcwBXAGkAbgBDAG8AbgB0AHIAbwBsAHMAFCRWAGkAcwB1AEUAbABlAG0AVABlAHgAdABFAGQAaQB0AG8AcgAVIlYAaQBzAHUATgBhAHQAaQB2AGUAQwBvAG4AdAByAG8AbAAWFHYAaQBzAHUAaQBuAHAAdQB0AHMAFwxzAHkAcwB0AGUAbQAYGFYAaQBzAHUARQBsAGUAbQBCAGEAcwBlABkmRABlAHYAUABsAGEAYwBlAGgAbwBsAGQAZQByAHMAVQBzAGUAZAAaCGIAbwBvAGwAGyJQAGwAdQBnAGkAbgBDAG8AbgBzAHQAcgBhAGkAbgB0AHMAHEx7ADQAMwBkADUAMgBiAGMAZQAtADkANAAyAGMALQA0ADQAZAA3AC0AOQBlADkANAAtADEAYgBmAGQAZgAzADEAMABlADYAMwBjAH0AHRxBAHQATABlAGEAcwB0AFYAZQByAHMAaQBvAG4AHhRQAGwAdQBnAGkAbgBHAHUAaQBkAB8WUwB5AHMAdABlAG0ALgBHAHUAaQBkACBIYQBmAGMAZAA1ADQANAA2AC0ANAA5ADEANAAtADQAZgBlADcALQBiAGIANwA4AC0AOQBiAGYAZgBlAGIANwAwAGYAZAAxADcAIRRVAHAAZABhAHQAZQBJAG4AZgBvACJMewBiADAAMwAzADYANgBhADgALQBiADUAYwAwAC0ANABiADkAYQAtAGEAMAAwAGUALQBlAGIAOAA2ADAAMQAxADEAMAA0AGMAMwB9ACMOVQBwAGQAYQB0AGUAcwAkTHsAMQA4ADYAOABmAGYAYwA5AC0AZQA0AGYAYwAtADQANQAzADIALQBhAGMAMAA2AC0AMQBlADMAOQBiAGIANQA1ADcAYgA2ADkAfQAlTHsAYQA1AGIAZAA0ADgAYwAzAC0AMABkADEANwAtADQAMQBiADUALQBiADEANgA0AC0ANQBmAGMANgBhAGQAMgBiADkANgBiADcAfQAmFk8AYgBqAGUAYwB0AHMAVAB5AHAAZQAnVFUAcABkAGEAdABlAEwAYQBuAGcAdQBhAGcAZQBNAG8AZABlAGwARgBvAHIAQwBvAG4AdgBlAHIAdABpAGIAbABlAEwAaQBiAHIAYQByAGkAZQBzACgQTABpAGIAVABpAHQAbABlACkUTABpAGIAQwBvAG0AcABhAG4AeQAqHlUAcABkAGEAdABlAFAAcgBvAHYAaQBkAGUAcgBzACs4UwB5AHMAdABlAG0ALgBDAG8AbABsAGUAYwB0AGkAbwBuAHMALgBIAGEAcwBoAHQAYQBiAGwAZQAsEnYAaQBzAHUAZQBsAGUAbQBzAC1INgBjAGIAMQBjAGQAZQAxAC0AZAA1AGQAYwAtADQAYQAzAGIALQA5ADAANQA0AC0AMgAxAGYAYQA3ADUANgBhADMAZgBhADQALihJAG4AdABlAHIAZgBhAGMAZQBWAGUAcgBzAGkAbwBuAEkAbgBmAG8AL0x7AGMANgAxADEAZQA0ADAAMAAtADcAZgBiADkALQA0AGMAMwA1AC0AYgA5AGEAYwAtADQAZQAzADEANABiADUAOQA5ADYANAAzAH0AMBhNAGEAagBvAHIAVgBlAHIAcwBpAG8AbgAxGE0AaQBuAG8AcgBWAGUAcgBzAGkAbwBuADIMTABlAGcAYQBjAHkAMzBMAGEAbgBnAHUAYQBnAGUATQBvAGQAZQBsAFYAZQByAHMAaQBvAG4ASQBuAGYAbwA0MEwAbwBhAGQATABpAGIAcgBhAHIAaQBlAHMASQBuAHQAbwBQAHIAbwBqAGUAYwB0ADUaQwBvAG0AcABhAHQAaQBiAGkAbABpAHQAeQDQAAIaA9ADAS0E0AUGGgfQBwgaAUUHCQjQAAkaBEUKCwQDAAAABQAAAA0AAAAAAAAA0AwLrQIAAADQDQEtDtAPAS0Q0AAJGgRFCgsEAwAAAAUAAAANAAAAKAAAANAMC60BAAAA0A0BLRHQDwEtENAACRoERQoLBAMAAAAFAAAADQAAAAAAAADQDAutAgAAANANAS0S0A8BLRDQAAkaBEUKCwQDAAAABQAAAA0AAAAUAAAA0AwLrQIAAADQDQEtE9APAS0Q0AAJGgRFCgsEAwAAAAUAAAANAAAAAAAAANAMC60CAAAA0A0BLRTQDwEtENAACRoERQoLBAMAAAAFAAAADQAAAAAAAADQDAutAgAAANANAS0V0A8BLRDQAAkaBEUKCwQDAAAABQAAAA0AAAAAAAAA0AwLrQIAAADQDQEtFtAPAS0X0AAJGgRFCgsEAwAAAAUAAAANAAAAKAAAANAMC60EAAAA0A0BLRjQDwEtENAZGq0BRRscAdAAHBoCRR0LBAMAAAAFAAAADQAAAAAAAADQHh8tINAhIhoCRSMkAtAAJRoFRQoLBAMAAAADAAAAAAAAAAoAAADQJgutAAAAANADAS0n0CgBLRHQKQEtENAAJRoFRQoLBAMAAAADAAAAAAAAAAoAAADQJgutAQAAANADAS0n0CgBLRHQKQEtEJoqKwFFAAEC0AABLSzQAAEtF9AAHy0t0C4vGgPQMAutAQAAANAxC60XAAAA0DIarQDQMy8aA9AwC60CAAAA0DELrQMAAADQMhqtANA0Gq0A0DUarQA=
174 |
175 |
176 | {192FAD59-8248-4824-A8DE-9177C94C195A}
177 |
178 | "{192FAD59-8248-4824-A8DE-9177C94C195A}"
179 |
180 |
181 |
182 | {F66C7017-BDD8-4114-926C-81D6D687E35F}
183 |
184 | "{F66C7017-BDD8-4114-926C-81D6D687E35F}"
185 |
186 |
187 |
188 | {246001F4-279D-43AC-B241-948EB31120E1}
189 |
190 | "{246001F4-279D-43AC-B241-948EB31120E1}"
191 |
192 |
193 | GlobalVisuImageFilePath
194 | %APPLICATIONPATH%
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 | System.Collections.Hashtable
203 | {54dd0eac-a6d8-46f2-8c27-2f43c7e49861}
204 | System.String
205 |
206 |
207 |
208 |
209 |
--------------------------------------------------------------------------------
/src/TcLogProj/TcLog/Utils/AnyToString.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
35 |
36 |
117 |
118 |
119 |
--------------------------------------------------------------------------------
/src/TcLogProj/TcLog/Utils/DateTime.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
16 |
17 |
40 |
41 |
42 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
121 |
122 | Tc2_Standard.LEN(timeString) THEN
138 | FOR i:=1 TO length - Tc2_Standard.LEN(timeString) DO
139 | replaceString := Tc2_Standard.CONCAT(replaceString, '0');
140 | END_FOR
141 | replaceString := Tc2_Standard.CONCAT(replaceString, timeString);
142 | ELSE
143 | replaceString := Tc2_Standard.RIGHT(timeString, length);
144 | END_IF
145 |
146 | ReplaceFormatPlaceholder := Tc2_Standard.REPLACE(format, replaceString, length, Tc2_Standard.FIND(format, timeType));]]>
147 |
148 |
149 |
150 | _20210812-12:30:22:123_
162 | {attribute 'hide_all_locals'}
163 | METHOD ToFormatString : Tc2_System.T_MaxString
164 | VAR_INPUT
165 | /// Format the timestamp should have.
166 | format : STRING;
167 | END_VAR
168 | VAR_INST
169 | inputString : STRING;
170 | c : STRING(1);
171 | formattedString : Tc2_System.T_MaxString;
172 | END_VAR
173 | VAR
174 | year : INT := 0;
175 | month : INT := 0;
176 | day : INT := 0;
177 | hour : INT := 0;
178 | minute : INT := 0;
179 | second : INT := 0;
180 | millisecond : INT := 0;
181 | END_VAR
182 | VAR CONSTANT
183 | ValidFormat : STRING := 'YMDhms';
184 | END_VAR
185 | ]]>
186 |
187 | 0 DO
191 | c := Tc2_Standard.LEFT(inputString, 1);
192 |
193 | IF c = 'Y' THEN year := year + 1;
194 | ELSIF c = 'M' THEN month := month + 1;
195 | ELSIF c = 'D' THEN day := day + 1;
196 | ELSIF c = 'h' THEN hour := hour + 1;
197 | ELSIF c = 'm' THEN minute := minute + 1;
198 | ELSIF c = 's' THEN second := second + 1;
199 | ELSIF c = 'i' THEN millisecond := millisecond + 1;
200 | END_IF
201 |
202 | inputString := Tc2_Standard.DELETE(inputString, 1, 1);
203 | END_WHILE
204 |
205 | formattedString := ReplaceFormatPlaceholder(format, year, 'Y');
206 | formattedString := ReplaceFormatPlaceholder(formattedString, month, 'M');
207 | formattedString := ReplaceFormatPlaceholder(formattedString, day, 'D');
208 | formattedString := ReplaceFormatPlaceholder(formattedString, hour, 'h');
209 | formattedString := ReplaceFormatPlaceholder(formattedString, minute, 'm');
210 | formattedString := ReplaceFormatPlaceholder(formattedString, second, 's');
211 | formattedString := ReplaceFormatPlaceholder(formattedString, millisecond, 'i');
212 |
213 | ToFormatString := formattedString;
214 |
215 |
216 | ]]>
217 |
218 |
219 |
220 |
--------------------------------------------------------------------------------
/src/TcLogProj/TcLog/Utils/DeleteOldFiles.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
35 |
36 | _enumFindFileList.nFindFiles THEN
72 | _state := DeleteFilesState.Idle;
73 | ELSE
74 | _state := DeleteFilesState.CheckIfFileIsDirectory;
75 | END_IF
76 |
77 | DeleteFilesState.CheckIfFileIsDirectory:
78 | IF NOT _listOfFiles[_deleteFileIndex].fileAttributes.bDirectory THEN
79 | _state := DeleteFilesState.CheckFileTime;
80 | ELSE
81 | _deleteFileIndex := _deleteFileIndex + 1;
82 | _state := DeleteFilesState.ProcessFoundFiles;
83 | END_IF
84 |
85 | DeleteFilesState.CheckFileTime:
86 | IF GetFileAgeInSeconds(CurrentUtcTime, _listOfFiles[_deleteFileIndex]) > (ExpirationInDays * OneDayInSeconds) THEN
87 | _state := DeleteFilesState.DeleteFile;
88 | ELSE
89 | _deleteFileIndex := _deleteFileIndex + 1;
90 | _state := DeleteFilesState.ProcessFoundFiles;
91 | END_IF
92 |
93 | DeleteFilesState.DeleteFile:
94 | _fileNameToDelete := Tc2_Standard.CONCAT(FilePath, _listOfFiles[_deleteFileIndex].sFileName);
95 | _startFileDelete := TRUE;
96 |
97 | IF _fileDeleteBusy.Q THEN
98 | _deleteFileIndex := _deleteFileIndex + 1;
99 | _fileDeleted := TRUE;
100 | _state := DeleteFilesState.FileDeleted;
101 | END_IF
102 | IF _fileDelete.bError THEN
103 | _state := DeleteFilesState.Idle;
104 | END_IF
105 |
106 | DeleteFilesState.FileDeleted:
107 | // This state is needed to generate a rising edge for FB_FileDelete
108 | IF NOT _fileDeleted THEN
109 | _state := DeleteFilesState.ProcessFoundFiles;
110 | END_IF
111 | _fileDeleted := FALSE;
112 |
113 | END_CASE
114 |
115 | // Function blocks used in state machine
116 |
117 | // Search files in given directory
118 | _enumFindFileList(sNetId := '',
119 | eCmd := _commandType,
120 | sPathName := Tc2_Standard.CONCAT(FilePath, Tc2_Standard.CONCAT('*', FileName)),
121 | bExecute := (_state = DeleteFilesState.SearchNextFile) OR (_commandType = eEnumCmd_Abort AND _state <> DeleteFilesState.Idle),
122 | pFindList := ADR(_listOfFiles),
123 | cbFindList := SIZEOF(_listOfFiles),
124 | tTimeout := T#10S);
125 |
126 | _enumBusy(CLK:=_enumFindFileList.bBusy);
127 |
128 | // Delete files
129 | _fileDelete(sNetId := '',
130 | sPathName := _fileNameToDelete,
131 | bExecute := _startFileDelete,
132 | tTimeout := T#10S);
133 |
134 | _fileDeleteBusy(CLK := _fileDelete.bBusy);
135 |
136 | // Error handling
137 | Error.Active := FALSE;
138 | Error.Code := ErrorCodes.None;
139 | Error.Info := '';
140 |
141 | IF _enumFindFileList.bError THEN
142 | Error.Active := TRUE;
143 | Error.Code := ErrorCodes.EnumeratingFilesInSpecifiedDirectoryFailed;
144 | Error.Info := Tc2_Standard.CONCAT('Enumerating files in specified directory failed. Error thrown by FB_EnumFindFileList. Consult Beckhoff InfoSys. Internal Error: ', UDINT_TO_STRING(_enumFindFileList.nErrId));
145 | END_IF
146 |
147 | IF _fileDelete.bError THEN
148 | Error.Active := TRUE;
149 | Error.Code := ErrorCodes.DeletingFileFailed;
150 | Error.Info := Tc2_Standard.CONCAT('Deleting expired log file in specified directory failed. Error thrown by FB_FileDelete. Consult Beckhoff InfoSys. Internal Error: ', UDINT_TO_STRING(_fileDelete.nErrId));
151 | END_IF]]>
152 |
153 |
154 |
--------------------------------------------------------------------------------
/src/TcLogProj/TcLog/Utils/DynamicStringBuffer.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
18 |
19 |
20 |
21 |
26 |
27 |
29 |
30 |
31 |
32 |
37 |
38 |
40 |
41 |
42 |
43 |
48 |
49 |
52 |
53 |
54 |
55 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
78 |
79 |
80 |
81 |
82 |
83 |
85 |
86 |
87 |
88 |
89 |
90 |
95 |
96 |
97 |
98 |
99 |
100 |
131 |
132 | 0 AND enable THEN
141 | lockFileWriteToForceRisingEdge := FALSE;
142 | state := PersistToFileState.OpenFile;
143 | END_IF
144 | END_IF
145 |
146 | // *** O P E N F I L E ***
147 | fileOpen(sNetId := NetId, sPathName := fileName, nMode := FOPEN_MODEAPPEND OR FOPEN_MODETEXT,
148 | ePath := PATH_GENERIC, bExecute := (state = PersistToFileState.OpenFile), tTimeout := Timeout,
149 | hFile => fileHandle);
150 |
151 | IF state = PersistToFileState.OpenFile THEN
152 | IF fileOpen.bError THEN
153 | state := PersistToFileState.CloseFile;
154 | ELSIF NOT fileOpen.bBusy THEN
155 | state := PersistToFileState.GetStringFromFifo;
156 | END_IF
157 | END_IF
158 |
159 | // *** P O P F R O M F I F O ***
160 | IF state = PersistToFileState.GetStringFromFifo THEN
161 | IF NOT lockFileWriteToForceRisingEdge THEN
162 | currentBufferPos := 0;
163 | FOR i:=0 TO MaxLogsPerCycle DO
164 | IF _fifo.nCount <= 0 THEN EXIT; END_IF
165 | IF currentBufferPos >= MaxBufferPosition THEN EXIT; END_IF
166 |
167 | _fifo.A_RemoveHead(getValue => fifoHeadString);
168 | fifoHeadBytes := MAXSTRING_TO_BYTEARR(fifoHeadString);
169 | fifoHeadLength := INT_TO_UDINT(LEN(fifoHeadString));
170 | MEMCPY(
171 | destAddr := ADR(buffer) + SIZEOF(BYTE) * currentBufferPos,
172 | srcAddr := ADR(fifoHeadBytes),
173 | n := fifoHeadLength);
174 | currentBufferPos := currentBufferPos + fifoHeadLength;
175 | END_FOR
176 | state := PersistToFileState.AppendDataToFile;
177 | END_IF
178 | lockFileWriteToForceRisingEdge := FALSE;
179 | END_IF
180 |
181 | // *** W R I T E T O F I L E ***
182 | fileWrite(
183 | sNetId := NetId,
184 | hFile := fileHandle,
185 | pWriteBuff := ADR(buffer),
186 | cbWriteLen := currentBufferPos,
187 | bExecute := state = PersistToFileState.AppendDataToFile,
188 | tTimeout := Timeout);
189 |
190 | IF state = PersistToFileState.AppendDataToFile THEN
191 | lockFileWriteToForceRisingEdge := TRUE;
192 | IF fileWrite.bError THEN
193 | state := PersistToFileState.CloseFile;
194 | ELSIF _fifo.nCount > 0 AND NOT fileWrite.bBusy THEN
195 | state := PersistToFileState.GetStringFromFifo;
196 | ELSIF _fifo.nCount = 0 THEN
197 | state := PersistToFileState.CloseFile;
198 | END_IF
199 | END_IF
200 |
201 | // *** C L O S E F I L E ***
202 | fileClose(
203 | sNetId := NetId, hFile := fileHandle,
204 | bExecute := (state = PersistToFileState.CloseFile), tTimeout := Timeout);
205 |
206 | IF state = PersistToFileState.CloseFile THEN
207 | IF NOT fileClose.bBusy THEN state := PersistToFileState.Idle; END_IF
208 | END_IF
209 |
210 | // Close file in case of error
211 | IF fileOpen.bError THEN state := PersistToFileState.CloseFile; END_IF
212 | IF fileWrite.bError THEN state := PersistToFileState.CloseFile; END_IF
213 | IF NOT _fifo.bOk AND _fifo.nCount > 0 AND state <> PersistToFileState.Idle THEN
214 | state := PersistToFileState.CloseFile;
215 | END_IF
216 |
217 | // Error handling
218 | IF fileOpen.bError THEN
219 | Error.Active := TRUE;
220 | Error.Code := ErrorCodes.OpeningFileFailed;
221 | Error.Info := Tc2_Standard.CONCAT('Opening file failed. Error thrown by FB_FileOpen. Consult Beckhoff InfoSys. Internal Error: ', UDINT_TO_STRING(fileOpen.nErrId));
222 | ELSIF fileWrite.bError THEN
223 | Error.Active := TRUE;
224 | Error.Code := ErrorCodes.WritingToFileFailed;
225 | Error.Info := Tc2_Standard.CONCAT('Writing to file failed. Error thrown by FB_FileWrite. Consult Beckhoff InfoSys. Internal Error: ', UDINT_TO_STRING(fileWrite.nErrId));
226 | ELSIF fileClose.bError THEN
227 | Error.Active := TRUE;
228 | Error.Code := ErrorCodes.ClosingFileFailed;
229 | Error.Info := Tc2_Standard.CONCAT('Closing file failed. Error thrown by FB_FileClose. Consult Beckhoff InfoSys. Internal Error: ', UDINT_TO_STRING(fileClose.nErrId));
230 | ELSIF NOT _fifo.bOk AND _fifo.nCount > 0 THEN
231 | Error.Active := TRUE;
232 | Error.Code := ErrorCodes.FifoOverflow;
233 | Error.Info := 'FIFO overflow. Check if plc has enough free memory.';
234 | ELSE
235 | Error.Active := FALSE;
236 | Error.Code := ErrorCodes.None;
237 | Error.Info := '';
238 | END_IF
239 |
240 | // Set busy state
241 | Busy := (state <> PersistToFileState.Idle OR _fifo.nCount > 0);
242 |
243 | (* Uncomment for cyclic logging of state machine, buffer usage & errors
244 |
245 | ADSLOGSTR(ADSLOG_MSGTYPE_LOG,
246 | Tc2_Standard.CONCAT('****DynamicStringBuffer.state:',
247 | Tc2_Standard.CONCAT(UINT_TO_STRING(state),
248 | Tc2_Standard.CONCAT(', DynamicStringBuffer.hFile:', UINT_TO_STRING(hFile)))), '');
249 |
250 | ADSLOGSTR(ADSLOG_MSGTYPE_LOG,
251 | Tc2_Standard.CONCAT('****Fifo: used ',
252 | Tc2_Standard.CONCAT(UDINT_TO_STRING(Fifo.cbSize),
253 | Tc2_Standard.CONCAT(' of ', UDINT_TO_STRING(Fifo.cbBuffer)))), '');
254 |
255 | IF Error.Active THEN
256 | ADSLOGSTR(ADSLOG_MSGTYPE_LOG,
257 | Tc2_Standard.CONCAT('****DynamicStringBuffer.Error: ', Error.Info),
258 | '');
259 | END_IF
260 | *)]]>
261 |
262 |
263 |
264 |
269 |
270 | headString);
271 | PopHead := headString;]]>
272 |
273 |
274 |
275 |
282 |
283 | _fifo.cbBuffer THEN
286 | _dynamicMemoryBuffer.Resize(nSize := requiredSize*SIZEOF(BYTE), bPreserve:=TRUE, bReset:=TRUE);
287 | _fifo.pBuffer := _dynamicMemoryBuffer.pBuffer;
288 | _fifo.cbBuffer := requiredSize;
289 | END_IF]]>
290 |
291 |
292 |
293 |
--------------------------------------------------------------------------------
/src/TcLogProj/TcLog/Utils/GenerateTimeData.TcPOU.bak:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
23 |
24 |
48 |
49 |
50 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
74 |
75 | LEN(timeString) THEN
89 | FOR i:=1 TO Length - LEN(timeString) DO
90 | replaceString := Tc2_Standard.CONCAT(replaceString, '0');
91 | END_FOR
92 | replaceString := Tc2_Standard.CONCAT(replaceString, timeString);
93 | ELSE
94 | replaceString := RIGHT(timeString, Length);
95 | END_IF
96 |
97 | ReplaceFormatPlaceholder := REPLACE(Format, replaceString, Length, FIND(Format, TimeType));]]>
98 |
99 |
100 |
101 | _20210812-12:30:22:123_
112 | METHOD ToString : Tc2_System.T_MaxString
113 | VAR_INPUT
114 | Format : STRING;
115 | END_VAR
116 | VAR_INST
117 | inputString : STRING;
118 | char : STRING(1);
119 | formattedString : Tc2_System.T_MaxString;
120 | END_VAR
121 | VAR
122 | year : INT := 0;
123 | month : INT := 0;
124 | day : INT := 0;
125 | hour : INT := 0;
126 | minute : INT := 0;
127 | second : INT := 0;
128 | millisecond : INT := 0;
129 | END_VAR
130 | VAR CONSTANT
131 | VALID_FORMAT : STRING := 'YMDhms';
132 | END_VAR
133 | ]]>
134 |
135 | 0 DO
139 | char := LEFT(inputString, 1);
140 |
141 | IF char = 'Y' THEN year := year + 1;
142 | ELSIF char = 'M' THEN month := month + 1;
143 | ELSIF char = 'D' THEN day := day + 1;
144 | ELSIF char = 'h' THEN hour := hour + 1;
145 | ELSIF char = 'm' THEN minute := minute + 1;
146 | ELSIF char = 's' THEN second := second + 1;
147 | ELSIF char = 'i' THEN millisecond := millisecond + 1;
148 | END_IF
149 |
150 | inputString := DELETE(inputString, 1, 1);
151 | END_WHILE
152 |
153 | formattedString := ReplaceFormatPlaceholder(Format, year, 'Y');
154 | formattedString := ReplaceFormatPlaceholder(formattedString, month, 'M');
155 | formattedString := ReplaceFormatPlaceholder(formattedString, day, 'D');
156 | formattedString := ReplaceFormatPlaceholder(formattedString, hour, 'h');
157 | formattedString := ReplaceFormatPlaceholder(formattedString, minute, 'm');
158 | formattedString := ReplaceFormatPlaceholder(formattedString, second, 's');
159 | formattedString := ReplaceFormatPlaceholder(formattedString, millisecond, 'i');
160 |
161 | ToString := formattedString;
162 |
163 |
164 | ]]>
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
--------------------------------------------------------------------------------
/src/TcLogProj/TcLog/Utils/GetFileAgeInSeconds.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
19 |
20 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/src/TcLogProj/TcLog/Utils/_DataTypes/DeleteFilesState.TcDUT:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
20 |
21 |
--------------------------------------------------------------------------------
/src/TcLogProj/TcLog/Utils/_DataTypes/PersistToFileState.TcDUT:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
18 |
--------------------------------------------------------------------------------
/src/TcLogProj/TcLog/Utils/_Tests/ConvertAnyToString_TEST.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 |
27 |
28 |
29 |
37 |
38 |
48 |
49 |
50 |
51 |
58 |
59 |
68 |
69 |
70 |
71 |
78 |
79 |
88 |
89 |
90 |
91 |
99 |
100 |
110 |
111 |
112 |
113 |
120 |
121 |
130 |
131 |
132 |
133 |
141 |
142 |
152 |
153 |
154 |
155 |
163 |
164 |
174 |
175 |
176 |
177 |
185 |
186 |
196 |
197 |
198 |
199 |
207 |
208 |
218 |
219 |
220 |
221 |
229 |
230 |
240 |
241 |
242 |
243 |
251 |
252 |
262 |
263 |
264 |
265 |
273 |
274 |
284 |
285 |
286 |
287 |
294 |
295 |
304 |
305 |
306 |
307 |
314 |
315 |
324 |
325 |
326 |
327 |
334 |
335 |
344 |
345 |
346 |
347 |
355 |
356 |
366 |
367 |
368 |
369 |
377 |
378 |
388 |
389 |
390 |
391 |
399 |
400 |
410 |
411 |
412 |
413 |
421 |
422 |
432 |
433 |
434 |
435 |
443 |
444 |
454 |
455 |
456 |
457 |
464 |
465 |
474 |
475 |
476 |
477 |
483 |
484 |
485 |
486 |
487 |
488 |
--------------------------------------------------------------------------------
/src/TcLogProj/TcLog/Utils/_Tests/DateTime_TEST.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 |
8 |
9 |
10 |
20 |
21 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/src/TcLogProj/TcLog/Utils/_Tests/DynamicStringBuffer_TEST.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 |
8 |
9 |
10 |
26 |
27 | 0 THEN
48 | result := logsManyMessagesForManyCyclesLogger.Error.Info;
49 | END_IF
50 |
51 | IF cycleCount > (Cycles * Messages * 2 + 4) THEN
52 | AssertEquals(Expected := expected,
53 | Actual := result,
54 | Message := result);
55 |
56 | TEST_FINISHED();
57 | END_IF]]>
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/src/TcLogProj/TcLogProj.tsproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | PlcTask1
11 |
12 |
13 |
14 |
15 |
16 |
17 | TcLog Instance
18 | {08500001-0000-0000-F000-000000000064}
19 |
20 |
21 | 1
22 | Default
23 |
24 |
25 |
26 |
27 |
28 |
29 | TcLogTEST Instance
30 | {08500001-0000-0000-F000-000000000064}
31 |
32 |
33 | 0
34 | PlcTask
35 |
36 | #x02010040
37 |
38 | 21
39 | 10000000
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/src/TcLogProj/TcLogTEST/PlcTask.TcTTO:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 10000
6 | 21
7 |
8 | TESTS
9 |
10 | {8c69b6b0-46d1-4425-bb87-a907c774dc33}
11 | {4c28a96c-efe9-4f21-a0c4-de877f1be764}
12 | {3bfdb96d-f68b-400e-8a1d-b0e47fdbf9ff}
13 | {2307b5ee-67e0-4083-b767-e9782c3843a0}
14 | {749f2c86-938a-4721-846a-b2cbd4d2332d}
15 |
16 |
--------------------------------------------------------------------------------
/src/TcLogProj/TcLogTEST/TESTS.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/TcLogProj/TcLogTEST/TcLogTEST.plcproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | 1.0.0.0
4 | 2.0
5 | {39e514bf-8337-4e82-99ca-d7d99beee7fe}
6 | True
7 | true
8 | true
9 | false
10 | TcLogTEST
11 | 3.1.4026.12
12 | {8146f613-9e7d-40c5-8b31-c45750c652a0}
13 | {fbd87f5e-6357-460c-8b4e-eca3de6b406a}
14 | {1f1d2e22-83eb-4b46-b927-71cab86c9b53}
15 | {318c4518-ff6d-4f11-9dc5-2c14ca6d4e2f}
16 | {18d37d59-7d3c-4061-9c13-6219439268ab}
17 | {83fa6c17-9059-4e97-8066-14e4551621aa}
18 |
19 |
20 |
21 | Code
22 |
23 |
24 | Code
25 |
26 |
27 |
28 |
29 | Tc2_Standard, * (Beckhoff Automation GmbH)
30 | Tc2_Standard
31 |
32 |
33 | Tc2_System, * (Beckhoff Automation GmbH)
34 | Tc2_System
35 |
36 |
37 | Tc3_Module, * (Beckhoff Automation GmbH)
38 | Tc3_Module
39 |
40 |
41 | TcLog, * (Benedikt Geisler)
42 |
43 |
44 | TcUnit, * (www.tcunit.org)
45 | TcUnit
46 |
47 |
48 |
49 |
50 | Content
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 | "<ProjectRoot>"
59 |
60 | {192FAD59-8248-4824-A8DE-9177C94C195A}
61 |
62 | "{192FAD59-8248-4824-A8DE-9177C94C195A}"
63 |
64 |
65 |
66 | {246001F4-279D-43AC-B241-948EB31120E1}
67 |
68 | "{246001F4-279D-43AC-B241-948EB31120E1}"
69 |
70 |
71 | GlobalVisuImageFilePath
72 | %APPLICATIONPATH%
73 |
74 |
75 | {29BD8D0C-3586-4548-BB48-497B9A01693F}
76 |
77 | "{29BD8D0C-3586-4548-BB48-497B9A01693F}"
78 |
79 | Rules
80 |
81 | "Rules"
82 |
83 |
84 |
85 |
86 |
87 |
88 | {40450F57-0AA3-4216-96F3-5444ECB29763}
89 |
90 | "{40450F57-0AA3-4216-96F3-5444ECB29763}"
91 |
92 |
93 | ActiveVisuProfile
94 | IR0whWr8bwfwBwAAiD2qpQAAAABVAgAA37x72QAAAAABAAAAAAAAAAEaUwB5AHMAdABlAG0ALgBTAHQAcgBpAG4AZwACTHsAZgA5ADUAYgBiADQAMgA2AC0ANQA1ADIANAAtADQAYgA0ADUALQA5ADQAMAAwAC0AZgBiADAAZgAyAGUANwA3AGUANQAxAGIAfQADCE4AYQBtAGUABDBUAHcAaQBuAEMAQQBUACAAMwAuADEAIABCAHUAaQBsAGQAIAA0ADAAMgA0AC4ANwAFFlAAcgBvAGYAaQBsAGUARABhAHQAYQAGTHsAMQA2AGUANQA1AGIANgAwAC0ANwAwADQAMwAtADQAYQA2ADMALQBiADYANQBiAC0ANgAxADQANwAxADMAOAA3ADgAZAA0ADIAfQAHEkwAaQBiAHIAYQByAGkAZQBzAAhMewAzAGIAZgBkADUANAA1ADkALQBiADAANwBmAC0ANABkADYAZQAtAGEAZQAxAGEALQBhADgAMwAzADUANgBhADUANQAxADQAMgB9AAlMewA5AGMAOQA1ADgAOQA2ADgALQAyAGMAOAA1AC0ANAAxAGIAYgAtADgAOAA3ADEALQA4ADkANQBmAGYAMQBmAGUAZABlADEAYQB9AAoOVgBlAHIAcwBpAG8AbgALBmkAbgB0AAwKVQBzAGEAZwBlAA0KVABpAHQAbABlAA4aVgBpAHMAdQBFAGwAZQBtAE0AZQB0AGUAcgAPDkMAbwBtAHAAYQBuAHkAEAxTAHkAcwB0AGUAbQARElYAaQBzAHUARQBsAGUAbQBzABIwVgBpAHMAdQBFAGwAZQBtAHMAUwBwAGUAYwBpAGEAbABDAG8AbgB0AHIAbwBsAHMAEyhWAGkAcwB1AEUAbABlAG0AcwBXAGkAbgBDAG8AbgB0AHIAbwBsAHMAFCRWAGkAcwB1AEUAbABlAG0AVABlAHgAdABFAGQAaQB0AG8AcgAVIlYAaQBzAHUATgBhAHQAaQB2AGUAQwBvAG4AdAByAG8AbAAWFHYAaQBzAHUAaQBuAHAAdQB0AHMAFwxzAHkAcwB0AGUAbQAYGFYAaQBzAHUARQBsAGUAbQBCAGEAcwBlABkmRABlAHYAUABsAGEAYwBlAGgAbwBsAGQAZQByAHMAVQBzAGUAZAAaCGIAbwBvAGwAGyJQAGwAdQBnAGkAbgBDAG8AbgBzAHQAcgBhAGkAbgB0AHMAHEx7ADQAMwBkADUAMgBiAGMAZQAtADkANAAyAGMALQA0ADQAZAA3AC0AOQBlADkANAAtADEAYgBmAGQAZgAzADEAMABlADYAMwBjAH0AHRxBAHQATABlAGEAcwB0AFYAZQByAHMAaQBvAG4AHhRQAGwAdQBnAGkAbgBHAHUAaQBkAB8WUwB5AHMAdABlAG0ALgBHAHUAaQBkACBIYQBmAGMAZAA1ADQANAA2AC0ANAA5ADEANAAtADQAZgBlADcALQBiAGIANwA4AC0AOQBiAGYAZgBlAGIANwAwAGYAZAAxADcAIRRVAHAAZABhAHQAZQBJAG4AZgBvACJMewBiADAAMwAzADYANgBhADgALQBiADUAYwAwAC0ANABiADkAYQAtAGEAMAAwAGUALQBlAGIAOAA2ADAAMQAxADEAMAA0AGMAMwB9ACMOVQBwAGQAYQB0AGUAcwAkTHsAMQA4ADYAOABmAGYAYwA5AC0AZQA0AGYAYwAtADQANQAzADIALQBhAGMAMAA2AC0AMQBlADMAOQBiAGIANQA1ADcAYgA2ADkAfQAlTHsAYQA1AGIAZAA0ADgAYwAzAC0AMABkADEANwAtADQAMQBiADUALQBiADEANgA0AC0ANQBmAGMANgBhAGQAMgBiADkANgBiADcAfQAmFk8AYgBqAGUAYwB0AHMAVAB5AHAAZQAnVFUAcABkAGEAdABlAEwAYQBuAGcAdQBhAGcAZQBNAG8AZABlAGwARgBvAHIAQwBvAG4AdgBlAHIAdABpAGIAbABlAEwAaQBiAHIAYQByAGkAZQBzACgQTABpAGIAVABpAHQAbABlACkUTABpAGIAQwBvAG0AcABhAG4AeQAqHlUAcABkAGEAdABlAFAAcgBvAHYAaQBkAGUAcgBzACs4UwB5AHMAdABlAG0ALgBDAG8AbABsAGUAYwB0AGkAbwBuAHMALgBIAGEAcwBoAHQAYQBiAGwAZQAsEnYAaQBzAHUAZQBsAGUAbQBzAC1INgBjAGIAMQBjAGQAZQAxAC0AZAA1AGQAYwAtADQAYQAzAGIALQA5ADAANQA0AC0AMgAxAGYAYQA3ADUANgBhADMAZgBhADQALihJAG4AdABlAHIAZgBhAGMAZQBWAGUAcgBzAGkAbwBuAEkAbgBmAG8AL0x7AGMANgAxADEAZQA0ADAAMAAtADcAZgBiADkALQA0AGMAMwA1AC0AYgA5AGEAYwAtADQAZQAzADEANABiADUAOQA5ADYANAAzAH0AMBhNAGEAagBvAHIAVgBlAHIAcwBpAG8AbgAxGE0AaQBuAG8AcgBWAGUAcgBzAGkAbwBuADIMTABlAGcAYQBjAHkAMzBMAGEAbgBnAHUAYQBnAGUATQBvAGQAZQBsAFYAZQByAHMAaQBvAG4ASQBuAGYAbwA0MEwAbwBhAGQATABpAGIAcgBhAHIAaQBlAHMASQBuAHQAbwBQAHIAbwBqAGUAYwB0ADUaQwBvAG0AcABhAHQAaQBiAGkAbABpAHQAeQDQAAIaA9ADAS0E0AUGGgfQBwgaAUUHCQjQAAkaBEUKCwQDAAAABQAAAA0AAAAAAAAA0AwLrQIAAADQDQEtDtAPAS0Q0AAJGgRFCgsEAwAAAAUAAAANAAAAKAAAANAMC60BAAAA0A0BLRHQDwEtENAACRoERQoLBAMAAAAFAAAADQAAAAAAAADQDAutAgAAANANAS0S0A8BLRDQAAkaBEUKCwQDAAAABQAAAA0AAAAUAAAA0AwLrQIAAADQDQEtE9APAS0Q0AAJGgRFCgsEAwAAAAUAAAANAAAAAAAAANAMC60CAAAA0A0BLRTQDwEtENAACRoERQoLBAMAAAAFAAAADQAAAAAAAADQDAutAgAAANANAS0V0A8BLRDQAAkaBEUKCwQDAAAABQAAAA0AAAAAAAAA0AwLrQIAAADQDQEtFtAPAS0X0AAJGgRFCgsEAwAAAAUAAAANAAAAKAAAANAMC60EAAAA0A0BLRjQDwEtENAZGq0BRRscAdAAHBoCRR0LBAMAAAAFAAAADQAAAAAAAADQHh8tINAhIhoCRSMkAtAAJRoFRQoLBAMAAAADAAAAAAAAAAoAAADQJgutAAAAANADAS0n0CgBLRHQKQEtENAAJRoFRQoLBAMAAAADAAAAAAAAAAoAAADQJgutAQAAANADAS0n0CgBLRHQKQEtEJoqKwFFAAEC0AABLSzQAAEtF9AAHy0t0C4vGgPQMAutAQAAANAxC60XAAAA0DIarQDQMy8aA9AwC60CAAAA0DELrQMAAADQMhqtANA0Gq0A0DUarQA=
95 |
96 |
97 | {8A0FB252-96EB-4DCC-A5B4-B4804D05E2D6}
98 |
99 | "{8A0FB252-96EB-4DCC-A5B4-B4804D05E2D6}"
100 |
101 |
102 | WriteLineIDs
103 | False
104 |
105 |
106 | {8F99A816-E488-41E4-9FA3-846536012284}
107 |
108 | "{8F99A816-E488-41E4-9FA3-846536012284}"
109 |
110 |
111 | DisabledWarningIds
112 | 5410
113 |
114 |
115 | {F66C7017-BDD8-4114-926C-81D6D687E35F}
116 |
117 | "{F66C7017-BDD8-4114-926C-81D6D687E35F}"
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 | System.Boolean
127 | System.Collections.Hashtable
128 | {54dd0eac-a6d8-46f2-8c27-2f43c7e49861}
129 | System.String
130 |
131 |
132 |
133 |
134 |
--------------------------------------------------------------------------------
/src/TcLogTest.NET/PersistingToFileSystem.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using Xunit;
4 | using System.IO;
5 | using System.Threading;
6 |
7 | namespace TcLogTest.NET
8 | {
9 | [Collection("Plc collection")]
10 | public class PersistingToFileSystem : IDisposable
11 | {
12 | PlcFixture fixture;
13 | readonly string mut = "TESTS.TestWrapper";
14 | readonly string path = "C:\\UnitTest\\";
15 | readonly string filename = "UnitTest.txt";
16 | readonly uint hPath;
17 | readonly uint hFileName;
18 |
19 | readonly uint hSystemTime;
20 | readonly uint hSetSystemTime;
21 | readonly uint hTime;
22 |
23 | public PersistingToFileSystem(PlcFixture fixture)
24 | {
25 | this.fixture = fixture;
26 |
27 | hPath = fixture.TcClient.CreateVariableHandle(mut + ".FilePath");
28 | hFileName = fixture.TcClient.CreateVariableHandle(mut + ".FileName");
29 | fixture.TcClient.WriteAny(hPath, path);
30 | fixture.TcClient.WriteAny(hFileName, filename);
31 |
32 | Directory.CreateDirectory(path);
33 | var files = Directory.GetFiles(path);
34 | foreach (var f in files) File.Delete(f);
35 |
36 | hSystemTime = fixture.TcClient.CreateVariableHandle(mut + ".NewLocalSystemTimeToBeSet");
37 | hSetSystemTime = fixture.TcClient.CreateVariableHandle(mut + ".TriggerNewLocalSystemTime");
38 | hTime = fixture.TcClient.CreateVariableHandle(mut + ".LocalTimeAsString");
39 | }
40 |
41 | public void Dispose()
42 | {
43 | fixture.TcClient.DeleteVariableHandle(hPath);
44 | fixture.TcClient.DeleteVariableHandle(hFileName);
45 | fixture.TcClient.DeleteVariableHandle(hSystemTime);
46 | fixture.TcClient.DeleteVariableHandle(hSetSystemTime);
47 | fixture.TcClient.DeleteVariableHandle(hTime);
48 | }
49 |
50 | private async Task SetTime(string setTime, string testTime)
51 | {
52 | fixture.TcClient.WriteAny(hSetSystemTime, false);
53 | fixture.TcClient.WriteAny(hSystemTime, setTime);
54 | fixture.TcClient.WriteAny(hSetSystemTime, true);
55 | while (fixture.TcClient.ReadAnyString(hTime, 80, System.Text.Encoding.ASCII).Contains(testTime) != true)
56 | await Task.Delay(200);
57 | fixture.TcClient.WriteAny(hSetSystemTime, false);
58 | }
59 |
60 | [Fact]
61 | public async void Persist_simple_error_message()
62 | {
63 | string message = "Simple message";
64 | uint hRun = fixture.TcClient.CreateVariableHandle(mut + ".Persist_simple_error_message_run");
65 | uint hData = fixture.TcClient.CreateVariableHandle(mut + ".Persist_simple_error_message_data");
66 |
67 | fixture.TcClient.WriteAny(hData, message);
68 | fixture.TcClient.WriteAny(hRun, true);
69 | await Task.Delay(1000);
70 | var files = Directory.GetFiles(path);
71 | var fileContent = File.ReadAllLines(files[0]);
72 |
73 | Assert.Contains(message, fileContent[0]);
74 | Assert.Contains("Error", fileContent[0]);
75 |
76 | foreach (var f in files) File.Delete(f);
77 | fixture.TcClient.DeleteVariableHandle(hRun);
78 | fixture.TcClient.DeleteVariableHandle(hData);
79 | }
80 |
81 | [Fact]
82 | public async void Persist_long_error_message()
83 | {
84 | string message = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata";
85 | uint hRun = fixture.TcClient.CreateVariableHandle(mut + ".Persist_long_error_message_run");
86 | uint hData = fixture.TcClient.CreateVariableHandle(mut + ".Persist_long_error_message_data");
87 |
88 | fixture.TcClient.WriteAny(hData, message);
89 | fixture.TcClient.WriteAny(hRun, true);
90 | await Task.Delay(1000);
91 | var files = Directory.GetFiles(path);
92 | var fileContent = File.ReadAllText(files[0]);
93 |
94 | Assert.Equal($"{message[..254]}\r\n", fileContent);
95 |
96 | foreach (var f in files) File.Delete(f);
97 | fixture.TcClient.DeleteVariableHandle(hRun);
98 | fixture.TcClient.DeleteVariableHandle(hData);
99 | }
100 |
101 | [Fact]
102 | public async void Linebreak_is_included_when_log_message_has_maximum_length()
103 | {
104 | string message = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata";
105 | uint hRun = fixture.TcClient.CreateVariableHandle(mut + ".Linebreak_is_included_when_log_message_has_maximum_length_run");
106 | uint hData = fixture.TcClient.CreateVariableHandle(mut + ".Linebreak_is_included_when_log_message_has_maximum_length_data");
107 |
108 | fixture.TcClient.WriteAny(hData, message);
109 | fixture.TcClient.WriteAny(hRun, true);
110 | await Task.Delay(1000);
111 | var files = Directory.GetFiles(path);
112 | var fileContent = File.ReadAllText(files[0]);
113 |
114 | Assert.Equal($"{message[..254]}\r\n{message[..254]}\r\n", fileContent);
115 |
116 | foreach (var f in files) File.Delete(f);
117 | fixture.TcClient.DeleteVariableHandle(hRun);
118 | fixture.TcClient.DeleteVariableHandle(hData);
119 | }
120 |
121 | [Fact]
122 | public async void Do_not_persist_logs_below_log_level()
123 | {
124 | uint hRun = fixture.TcClient.CreateVariableHandle(mut + ".Do_not_persist_logs_below_log_level_run");
125 |
126 | fixture.TcClient.WriteAny(hRun, true);
127 | await Task.Delay(1000);
128 | var files = Directory.GetFiles(path);
129 |
130 | Assert.Empty(files);
131 |
132 | fixture.TcClient.DeleteVariableHandle(hRun);
133 | }
134 |
135 | [Fact]
136 | public async void Log_message_contains_instance_path()
137 | {
138 | uint hRun = fixture.TcClient.CreateVariableHandle(mut + ".Log_message_contains_instance_path_run");
139 |
140 | fixture.TcClient.WriteAny(hRun, true);
141 | await Task.Delay(1000);
142 | var files = Directory.GetFiles(path);
143 | var fileContent = File.ReadAllLines(files[0]);
144 |
145 | Assert.Contains(mut, fileContent[0]);
146 |
147 | foreach (var f in files) File.Delete(f);
148 | fixture.TcClient.DeleteVariableHandle(hRun);
149 | }
150 |
151 | [Fact]
152 | public async void Log_message_uses_correct_delimiter()
153 | {
154 | string message = "Simple message";
155 | string delimiter = ";";
156 | uint hRun = fixture.TcClient.CreateVariableHandle(mut + ".Log_message_uses_correct_delimiter_run");
157 | uint hData = fixture.TcClient.CreateVariableHandle(mut + ".Log_message_uses_correct_delimiter_data");
158 | uint hDelimiter = fixture.TcClient.CreateVariableHandle(mut + ".delimiter");
159 |
160 | fixture.TcClient.WriteAny(hDelimiter, delimiter);
161 | fixture.TcClient.WriteAny(hData, message);
162 | fixture.TcClient.WriteAny(hRun, true);
163 | await Task.Delay(1000);
164 | var files = Directory.GetFiles(path);
165 | var fileContent = File.ReadAllLines(files[0]);
166 |
167 | Assert.Contains(delimiter + message, fileContent[0]);
168 |
169 | delimiter = "";
170 | fixture.TcClient.WriteAny(hDelimiter, delimiter);
171 | foreach (var f in files) File.Delete(f);
172 | fixture.TcClient.DeleteVariableHandle(hRun);
173 | fixture.TcClient.DeleteVariableHandle(hData);
174 | fixture.TcClient.DeleteVariableHandle(hDelimiter);
175 | }
176 |
177 | [Fact]
178 | public async void Log_message_contains_custom_formatted_timestamp()
179 | {
180 | uint hRun = fixture.TcClient.CreateVariableHandle(mut + ".Log_message_contains_custom_formatted_timestamp_run");
181 | fixture.TcClient.WriteAny(hRun, false);
182 |
183 | await SetTime("2021-08-17-22:05:01.300", "2021-08-17-22:05:");
184 | fixture.TcClient.WriteAny(hRun, true);
185 | await Task.Delay(1000);
186 | var files = Directory.GetFiles(path);
187 | var fileContent = File.ReadAllLines(files[0]);
188 |
189 | Assert.Contains("2021-08-17-22:05:", fileContent[0]);
190 |
191 | foreach (var f in files) File.Delete(f);
192 | fixture.TcClient.DeleteVariableHandle(hRun);
193 | }
194 |
195 | [Fact]
196 | public async void Delete_logs_if_expired()
197 | {
198 | uint hRun = fixture.TcClient.CreateVariableHandle(mut + ".Delete_logs_if_expired_run");
199 | fixture.TcClient.WriteAny(hRun, false);
200 | var files = Directory.GetFiles(path);
201 | foreach (var f in files) File.Delete(f);
202 |
203 | await SetTime("2021-08-17-19:59:58.300", "2021-08-17-19:59:");
204 | await Task.Delay(3000);
205 | fixture.TcClient.WriteAny(hRun, true);
206 | await Task.Delay(6000);
207 |
208 | await SetTime("2021-08-17-20:59:58.300", "2021-08-17-20:59:");
209 | await Task.Delay(3000);
210 | fixture.TcClient.WriteAny(hRun, true);
211 | await Task.Delay(6000);
212 |
213 | await SetTime("2021-08-17-21:59:58.300", "2021-08-17-21:59:");
214 | await Task.Delay(3000);
215 | fixture.TcClient.WriteAny(hRun, true);
216 | await Task.Delay(6000);
217 |
218 | await SetTime("2021-08-19-23:59:58.100", "2021-08-19-23:59:");
219 | await Task.Delay(4000);
220 | files = Directory.GetFiles(path);
221 |
222 | Assert.Empty(files);
223 |
224 | fixture.TcClient.DeleteVariableHandle(hRun);
225 | }
226 |
227 | [Fact]
228 | public async void New_logfile_is_created_if_rolling_interval_rolls()
229 | {
230 | uint hRun = fixture.TcClient.CreateVariableHandle(mut + ".New_logfile_is_created_if_rolling_interval_rolls_run");
231 | fixture.TcClient.WriteAny(hRun, false);
232 |
233 | await SetTime("2021-08-17-20:05:01.300", "2021-08-17-20:05:");
234 | fixture.TcClient.WriteAny(hRun, true);
235 | await Task.Delay(1000);
236 | await SetTime("2021-08-17-21:59:58.300", "2021-08-17-21:59:");
237 | await Task.Delay(3000);
238 | fixture.TcClient.WriteAny(hRun, true);
239 | await Task.Delay(3000);
240 | var files = Directory.GetFiles(path);
241 |
242 | Assert.True(files.Length == 2);
243 |
244 | foreach (var f in files) File.Delete(f);
245 | fixture.TcClient.DeleteVariableHandle(hRun);
246 | }
247 |
248 | [Fact]
249 | public async void Same_log_file_is_used_until_rolling_interval_rolls()
250 | {
251 | uint hRun = fixture.TcClient.CreateVariableHandle(mut + ".Same_log_file_is_used_until_rolling_interval_rolls");
252 | fixture.TcClient.WriteAny(hRun, false);
253 |
254 | await SetTime("2021-08-17-22:05:01.300", "2021-08-17-22:05:");
255 | fixture.TcClient.WriteAny(hRun, true);
256 | await Task.Delay(1000);
257 | fixture.TcClient.WriteAny(hRun, false);
258 | await Task.Delay(1000);
259 | fixture.TcClient.WriteAny(hRun, true);
260 | await Task.Delay(1000);
261 | var files = Directory.GetFiles(path);
262 |
263 | Assert.True(files.Length == 1);
264 |
265 | foreach (var f in files) File.Delete(f);
266 | fixture.TcClient.DeleteVariableHandle(hRun);
267 | }
268 |
269 | [Theory]
270 | [InlineData(1, 1000)]
271 | [InlineData(5, 1000)]
272 | [InlineData(10, 1000)]
273 | [InlineData(20, 2000)]
274 | [InlineData(100, 5000)]
275 | public async void Log_in_consecutive_cycles(int cycleCount, int waitTime)
276 | {
277 | uint hRun = fixture.TcClient.CreateVariableHandle(mut + ".Log_in_consecutive_cycles");
278 | uint hCycles = fixture.TcClient.CreateVariableHandle(mut + ".Number_of_log_cycles");
279 |
280 | fixture.TcClient.WriteAny(hCycles, cycleCount);
281 | fixture.TcClient.WriteAny(hRun, true);
282 | await Task.Delay(waitTime);
283 | var files = Directory.GetFiles(path);
284 |
285 | var fileContent = File.ReadAllLines(files[0]);
286 |
287 | Assert.Equal(cycleCount, fileContent.Length);
288 |
289 | fixture.TcClient.WriteAny(hCycles, 0);
290 | foreach (var f in files) File.Delete(f);
291 | fixture.TcClient.DeleteVariableHandle(hRun);
292 | fixture.TcClient.DeleteVariableHandle(hCycles);
293 | }
294 |
295 | [Theory]
296 | [InlineData(1, 1000)]
297 | [InlineData(5, 1000)]
298 | [InlineData(10, 1000)]
299 | [InlineData(20, 2000)]
300 | [InlineData(100, 5000)]
301 | public async void Log_multiple_times_in_one_cycle(int logCount, int waitTime)
302 | {
303 | uint hRun = fixture.TcClient.CreateVariableHandle(mut + ".Log_multiple_logs_in_one_cycle");
304 | uint hLogCount = fixture.TcClient.CreateVariableHandle(mut + ".Number_of_logs_per_cycle");
305 |
306 | fixture.TcClient.WriteAny(hLogCount, logCount);
307 | fixture.TcClient.WriteAny(hRun, true);
308 | await Task.Delay(waitTime);
309 | var files = Directory.GetFiles(path);
310 |
311 | var fileContent = File.ReadAllLines(files[0]);
312 |
313 | Assert.Equal(logCount, fileContent.Length);
314 |
315 | fixture.TcClient.WriteAny(hLogCount, 0);
316 | foreach (var f in files) File.Delete(f);
317 | fixture.TcClient.DeleteVariableHandle(hRun);
318 | fixture.TcClient.DeleteVariableHandle(hLogCount);
319 | }
320 |
321 | [Theory]
322 | [InlineData(5, 5, 500)]
323 | [InlineData(10, 10, 1_000)]
324 | [InlineData(20, 20, 2_000)]
325 | [InlineData(50, 50, 5_000)]
326 | [InlineData(5, 200, 2_000)]
327 | [InlineData(5, 500, 5_000)]
328 | [InlineData(20, 200, 10_000)]
329 | public async void Log_multiple_times_in_multiple_cycles(int cycleCount, int logCount, int waitTime)
330 | {
331 | uint hRun = fixture.TcClient.CreateVariableHandle(mut + ".Log_multiple_logs_in_multiple_cycles");
332 | uint hCyclesToLog = fixture.TcClient.CreateVariableHandle(mut + ".Number_of_cycles");
333 | uint hLogCount = fixture.TcClient.CreateVariableHandle(mut + ".Number_of_logs_per_cycle");
334 |
335 | fixture.TcClient.WriteAny(hCyclesToLog, cycleCount);
336 | fixture.TcClient.WriteAny(hLogCount, logCount);
337 | fixture.TcClient.WriteAny(hRun, true);
338 | await Task.Delay(waitTime);
339 | var files = Directory.GetFiles(path);
340 | var fileContent = File.ReadAllLines(files[0]);
341 |
342 | Assert.Equal(cycleCount * logCount, fileContent.Length);
343 |
344 | fixture.TcClient.WriteAny(hCyclesToLog, 0);
345 | fixture.TcClient.WriteAny(hLogCount, 0);
346 | foreach (var f in files) File.Delete(f);
347 | fixture.TcClient.DeleteVariableHandle(hRun);
348 | fixture.TcClient.DeleteVariableHandle(hCyclesToLog);
349 | fixture.TcClient.DeleteVariableHandle(hLogCount);
350 | }
351 |
352 | [Theory]
353 | [InlineData(1, 1, 1_000)]
354 | [InlineData(5, 5, 1_000)]
355 | [InlineData(10, 1, 1_000)]
356 | [InlineData(1, 10, 1_000)]
357 | [InlineData(10, 10, 5_000)]
358 | [InlineData(20, 20, 5_000)]
359 | [InlineData(50, 50, 5_000)]
360 | [InlineData(100, 50, 10_000)]
361 | [InlineData(5, 200, 2_000)]
362 | [InlineData(5, 500, 5_000)]
363 | public async void Persistance_time_stays_within_bounds(int cycleCount, int logCount, int waitTime)
364 | {
365 | const int MAX_LOGS_PER_CYCLE = 100;
366 | uint hRun = fixture.TcClient.CreateVariableHandle(mut + ".Persistance_time_stays_within_bounds");
367 | uint hCyclesToLog = fixture.TcClient.CreateVariableHandle(mut + ".Number_of_cycles");
368 | uint hLogCount = fixture.TcClient.CreateVariableHandle(mut + ".Number_of_logs_per_cycle");
369 | uint hDurationInCycles = fixture.TcClient.CreateVariableHandle(mut + ".Duration_in_cylces");
370 | int expectedCycles =
371 | logCount > MAX_LOGS_PER_CYCLE ?
372 | logCount / MAX_LOGS_PER_CYCLE * 3 * cycleCount :
373 | cycleCount;
374 |
375 | fixture.TcClient.WriteAny(hCyclesToLog, cycleCount);
376 | fixture.TcClient.WriteAny(hLogCount, logCount);
377 | fixture.TcClient.WriteAny(hDurationInCycles, 0);
378 | fixture.TcClient.WriteAny(hRun, true);
379 | await Task.Delay(waitTime);
380 | var files = Directory.GetFiles(path);
381 | var durationInCycles = fixture.TcClient.ReadAny(hDurationInCycles);
382 |
383 | Assert.InRange(durationInCycles, expectedCycles, expectedCycles * 1.5 + 2);
384 |
385 | fixture.TcClient.WriteAny(hCyclesToLog, 0);
386 | fixture.TcClient.WriteAny(hLogCount, 0);
387 | fixture.TcClient.WriteAny(hDurationInCycles, 0);
388 | foreach (var f in files) File.Delete(f);
389 | fixture.TcClient.DeleteVariableHandle(hRun);
390 | fixture.TcClient.DeleteVariableHandle(hCyclesToLog);
391 | fixture.TcClient.DeleteVariableHandle(hLogCount);
392 | fixture.TcClient.DeleteVariableHandle(hDurationInCycles);
393 | }
394 |
395 | [Fact]
396 | public void Persistence_in_first_cpu_cycle_has_correct_time_data_in_filename()
397 | {
398 | var files = Directory.GetFiles("C:\\UnitTestFirstCycle\\");
399 | var year = DateTime.Now.Year;
400 | var month = DateTime.Now.Month;
401 | var day = DateTime.Now.Day;
402 |
403 | foreach (var f in files)
404 | {
405 | Assert.DoesNotContain("1970", f);
406 | Assert.Contains(year.ToString(), f);
407 | Assert.Contains(month.ToString(), f);
408 | Assert.Contains(day.ToString(), f);
409 |
410 | // No file will be created if option ValidTimestampsOnly is set
411 | // as the first PLC cycle will not yet have valid time information
412 | Assert.DoesNotContain("firstCycleValidTimestampOnly", f);
413 | }
414 |
415 | foreach (var f in files) File.Delete(f);
416 | }
417 | }
418 | }
419 |
--------------------------------------------------------------------------------
/src/TcLogTest.NET/PlcFixture.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using TwinCAT.Ads;
5 | using Xunit;
6 |
7 | namespace TcLogTest.NET
8 | {
9 | public class PlcFixture : IDisposable
10 | {
11 | public PlcFixture()
12 | {
13 | TcClient = new AdsClient();
14 | TcClient.Connect(851);
15 | }
16 |
17 | public void Dispose()
18 | {
19 | TcClient.Dispose();
20 | }
21 |
22 | public AdsClient TcClient { get; private set; }
23 | }
24 |
25 | [CollectionDefinition("Plc collection")]
26 | public class PlcCollection : ICollectionFixture
27 | {
28 | // This class has no code, and is never created. Its purpose is simply
29 | // to be the place to apply [CollectionDefinition] and all the
30 | // ICollectionFixture<> interfaces.
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/TcLogTest.NET/TcLogTest.NET.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net7.0
5 |
6 | false
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/tools/release_library.ps1:
--------------------------------------------------------------------------------
1 | # This script prepares the library for release.
2 | # It takes a single parameter: the version number.
3 | # Usage: .\release_library.ps1 -version "1.0.0"
4 | # It:
5 | # - removes the TcUnit reference from the project
6 | # - sets the version number
7 | # - sets the release flag
8 | # - saves & installs the library
9 |
10 | param (
11 | [string]$version
12 | )
13 |
14 | if (-not $version) {
15 | Write-Host "Error: Version argument is required."
16 | exit 1
17 | }
18 |
19 | $ErrorActionPreference = "Stop"
20 |
21 | $plcProjectSourceDir = "C:\repos\TcLog\src\TcLogProj"
22 | $plcProjectTargetDir = "C:\TcLogLibraryRelease\TcLogProj"
23 | $plcProjectPath = "C:\TcLogLibraryRelease\TcLogProj\TcLogProj.tsproj"
24 |
25 | $slnDir = "C:\TcLogLibraryRelease"
26 | $slnName = "TcLogLibRelease"
27 |
28 | $librarySavePath = Join-Path -Path (Get-Location) -ChildPath "..\library\TcLog.library"
29 |
30 | # Copy the PLC project files to the target directory
31 | if (-not (Test-Path $plcProjectTargetDir)) {
32 | New-Item -ItemType Directory -Path $plcProjectTargetDir | Out-Null
33 | }
34 | Write-Host "Copying files from $plcProjectSourceDir to $plcProjectTargetDir..."
35 | Copy-Item -Path "$plcProjectSourceDir\*" -Destination $plcProjectTargetDir -Recurse -Force
36 | Write-Host "Files copied successfully."
37 |
38 | if ($null -eq $plcProjectPath -or -not (Test-Path $plcProjectPath)) {
39 | Write-Host "Error: PLC project path does not exist or is undefined: $plcProjectPath"
40 | exit 1
41 | }
42 |
43 | # Open Visual Studio and create a new solution
44 | $dte = new-object -com TcXaeShell.DTE.17.0
45 | try {
46 | $dte.SuppressUI = $false
47 | $dte.MainWindow.Visible = $true
48 | $solution = $dte.Solution
49 | Write-Host "Creating new solution..."
50 |
51 | # !! Variable assignments are needed to avoid some weird PS error !!
52 | $a = $solution.Create($slnDir, $slnName)
53 | Write-Host "Adding PLC project to solution..."
54 | $a = $solution.AddFromFile($plcProjectPath)
55 | Write-Host "Solution created and PLC project added successfully."
56 |
57 | $project = $solution.Projects.Item(1)
58 |
59 | # Remove the reference to TcUnit from the project
60 | Write-Host "Removing reference to TcUnit from the project..."
61 | $a = $project.Object.LookupTreeItem("TIPC^TcLog^TcLog Projekt^References").RemoveReference("TcUnit")
62 |
63 | # Set the version number
64 | $xml = "$version"
65 | $a = $project.Object.LookupTreeItem("TIPC^TcLog^TcLog Projekt").ConsumeXml($xml)
66 |
67 | # Set the release flag
68 | $xml = "true"
69 | $a = $project.Object.LookupTreeItem("TIPC^TcLog^TcLog Projekt").ConsumeXml($xml)
70 |
71 | # Save as library
72 | Write-Host "Saving PLC project as library..."
73 | $a = $project.Object.LookupTreeItem("TIPC^TcLog^TcLog Projekt").SaveAsLibrary($librarySavePath, $true)
74 | Write-Host "PLC project saved as library successfully."
75 |
76 | # Close the project
77 | Write-Host "Closing the project."
78 | $a = $dte.Quit()
79 |
80 | # Delete the project files
81 | Write-Host "Deleting the project files..."
82 | Remove-Item -Path "$plcProjectTargetDir\*" -Recurse -Force
83 | Write-Host "Project files deleted successfully."
84 | }
85 | catch {
86 | Write-Host "An error occurred: $_"
87 | $dte.Quit()
88 | }
89 |
--------------------------------------------------------------------------------