Logging various form of data is common practice and is done in some form in more or less every industrial application. There are various ways to store the data such as databases and different cloud services. However, sometimes you just want to stick to the basics and store data as a file, for instance as comma separated values (CSV). Depending on the amount of data that needs to be written, it’s usually not the best idea to do a lot of writes to the PLCs local drive because of wear and accessibility, but rather to a network drive.
To write single lines of strings to a file in TwinCAT I needed to use a three-stage rocket of different function blocks:
- FB_FileOpen – for opening a file (to append new lines to it)
- FB_FilePuts – for writing single strings to the file
- FB_FileClose – for closing the file
The FB_FileOpen returns a handle that the other two FBs are using as input. However, using FB_FileOpen on a network drive always returned an error with the error identity equal to 1804. Checking the documentation for ADS return codes it says ADSERR_DEVICE_NOTFOUND (not found (files, …)). I tried using it on a local drive, including a microSD card attached to the PLC and everything worked just fine. After spending some time trying to get it to work I quickly checked the documentation for FB_FileOpen and it was very clear with network drives:
sPathName: Path and file name for the file to be opened. The path can only point to the local computer’s file system. Network paths cannot be specified here.
This means we need to find a workaround. Initially I thought of writing a simple C# program running in Windows that simply monitored for new files in a directory and copied them over to the network drive. The problem with that would be that there would have to be some sort of communication with the TwinCAT software in order for the C# program to know when the file is finished. This is not optimal and surely there must be a way to do it entirely from PLC code. After some searching I found this really neat function block NT_StartProcess, which can be used to start a windows application on the local or on a remote PLC. In the old days I used to do all file handling in DOS. DOS as an operating system is long gone, but some remnants of it still remain in the cmd.exe (command prompt). In the command prompt we can use the move or copy commands. This means we could copy/move the file once we are finished with the write to it. The state machine for our application would be:
- Open the file on a local drive of the PLC (FB_FileOpen)
- Write to the file (FB_FilePuts)
- Close the file (FB_FileClose)
- Transfer the file from the PLC to the network drive (NT_StartProcess)
Starting cmd.exe in windows and checking the documentation for copy gives us:
C:\Users\Jakob>help copy Copies one or more files to another location. COPY [/D] [/V] [/N] [/Y | /-Y] [/Z] [/L] [/A | /B ] source [/A | /B] [+ source [/A | /B] [+ ...]] [destination [/A | /B]] source Specifies the file or files to be copied. /A Indicates an ASCII text file. /B Indicates a binary file. /D Allow the destination file to be created decrypted destination Specifies the directory and/or filename for the new file(s). /V Verifies that new files are written correctly. /N Uses short filename, if available, when copying a file with a non-8dot3 name. /Y Suppresses prompting to confirm you want to overwrite an existing destination file. /-Y Causes prompting to confirm you want to overwrite an existing destination file. /Z Copies networked files in restartable mode. /L If the source is a symbolic link, copy the link to the target instead of the actual file the source link points to.
There is a bunch of flags that can help us specify our request even more, but the basic command is “copy <sourcefile> <destinationfile>”. Next let’s look at the NT_StartProcess function block.
The PATHSTR refers to the complete path for the application that we want to run, in our case it is ‘C:\Windows\System32\cmd.exe’. The DIRNAME is the directory from which the application will be launched. This doesn’t matter too much for us, but we can just leave it as ‘C:\Windows\System32‘. Finally, the COMNDLINE input are the parameters that are going to be provided to cmd.exe. We can run commands in cmd.exe by calling cmd.exe with the /C flag, and everything that follows is the command that we want to run. So for instance to do a standard ping we would call cmd.exe /C “ping google.com”. In our case this means that the COMNDLINE input would be ‘/C “copy C:\PathToSourceFile.csv N:\PathToDestinationFile.csv”‘.
An example of a call to this FB might then look like this:
Trigger the execution of the function block with the START input.
Now that we got this to work, what about the wear on the PLCs local drive? This can be circumvented by making sure to enable the UWF (or FBFW), which stands for unified write filter. This redirects all writes to the memory of the PLC rather than to the disk. Although it from the perspective from Windows looks like the data is written to disk, it’s actually written to RAM.
The UWF can only be enabled for local drives, and does thus not affect the network drive which means that once the files are copied from the local drive (RAM) into the network drive, they are safely stored.
And that’s it for this post. Have you ever stored files with TwinCAT on a network drive, and have any good tricks for how this was accomplished? Please write a comment!
Hard drive by Blickpixel from www.pixabay.com
Hi Jakob,
what works with FB_FileOpen are Samba Shares. On Windows CE you don’t have UWF (to my knowledge; would be awesome, if it was), so I shared a folder on a Windows machine and connected that folder on Windows CE where my runtime was running. To be honest, I needed some hours to get it running on CE (on my Win7 machine I could connect to the share immediately) and to this day I don’t know what made it work to connect to the share. I haven’t tried it on a Linux (Samba) server, but I guess it should work fine with it too.
Greetings, Maxim
Hi Maxim! I actually tried it with Samba-shares in Win10 and TC4024.4, and it didn’t work. Might it be different how it works on WinCE vs. Win10(7)?
It should be more or less the same. In fact the CE implementation has more restrictions to it. For example, you have to use the hostname instead of the ip address to connect. Thats why you need to have a WINS server. In my case I chose the Windows machine with the shares itself. Also you don’t have drive letters like in Win7 and Win10, so I basically used the complete path like “\\hostname\path\to\shared\folder”.
Also, as I understand it, when you bind a drive letter to a share, it is up to Windows to make the abstraction so every program can use the share as if it’s a (local) partition.
I’ve tried all combinations, using both hostname and ip-address without success. I’ve had this through Beckhoff support, and they confirmed it’s not possible to do FB_FileOpen on network devices (just as the documentation says), though they did not mention whether there was something special with WinCE. If you manage to get it to work with a non-CE device using TwinCAT3, and can document how to do it, I’m sure to update this post 🙂
Well, that’s disappointing. I just tried and it really did not work. I will check again later, probably on the weekend. But it really seems like TwinCAT has no access to the path, even when binding to a drive letter. So maybe the shared folder functionality is worked into WinCE while on standard Win it’s only built into the Explorer.
I tried today and it still does not work, but my feeling is it is somehow related to the sharing/credential options.
I use TC3 in a Virtualbox Win7 VM on a Linux host. In this configuration I can access my shared folders from the host with ‘\\VBOXSVR\folder’ which is on a different partition and with a different filesystem. Also I can access locally shared folders by a network path. So it seems to me that TC can access network shares but it does not use credential information of other users. Maybe it would work when using a network domain, so the same user which runs the TC runtime could also access the shared folder on another computer, but my knowledge about Windows and networks is pretty rudimentary.
Thanks for your work/effort in this Maxim! Hopefully another reader of this blog has found a work-around and can contribute with a solution?
Hi Jakob,
Just curious to know if you experimented any problems with UWF in Win10?
I have used FBWF in Win7 for years without any problems. When I started testing UWF in Win10, I noticed a problem right away. If you exclude some folders or files from the write filter, these files will be persistent as expected, but they will still fill up the overlay. So eventually the overlay becomes full and the PC becomes very slow and eventually stops. That is not the expected behavior. Win7 FBWF does not have this problem. For this reason, I decided to stick to Win7 until this will be fixed. I told Beckhoff about this issue 1 or 2 years ago. I know it is not a Beckhoff issue but a Microsoft issue and I don’t think it has been fixed yet.
Here’s a post about this issue:
https://social.msdn.microsoft.com/Forums/en-US/1eb403e0-aff8-4e40-b092-2f841b81b097/unified-write-filter-uwf-not-working-on-windows-10-enterprise-ltsb?forum=WindowsIoT
And here’s a nice tool to monitor overlay consumption:
http://annabooks.com/SW_UWFUtility.html
Thank you.
Hi Yannick! I’ve read the thread and if this is still the case with UWF in the latest Beckhoff images it’s a problem compared with the FBWF in Win7. I don’t see how this can be according to design, it has to be a bug. I’ll do some tests on my own and drop an e-mail to Beckhoff as well and try to get their input on this.
Thanks for bringing this to my attention!
Update: I’ve written a blog post where I’ve investigated this further.
What works even better is to manually open an SMB connection using raw TCP-IP. It’s somewhat convoluted, but with judicious borrowing and rewriting of code from samba, it can be done in ~2000 lines. I probably need to post my experiments in that area.
That would be really fun to write. If you manage to do any experiments and don’t mind sharing the results, please post a link to the results!
It worked like a charm for me, I was really stuck I had no idea Twincat does not have access to networked location. Just one comment, if you try to copy the content of a folder to an existing one at a different location there is a prompt to confirm the data transfer. In order to avoid this you need a -Y so the string as input in COMMNDLINE of the NT_STARTPROCESS block should be
‘/C “copy C:\TwinCAT\Data.txt Y:\Data.txt /Y”‘
In addition to your contribution, I would like to add something because nobody has responded to the fact that the FB_File … blocks are designed for ADS communication. If the sNetId input remains empty (= ”), then the target system is local.
You can install the free ADS protocol on a remote system.
https://www.beckhoff.de/ Download / Software / TwinCAT 3 / TC1xxxx | Runtime / TC1000 | TC3.1 ADS version 3.1.4024.7
The AMS NetId of the target system must be entered in the Add Route Dialog of the TwinCAT PLC computer. FB_FileOpen.sNetId := ‘AMS NetID of the target system’ enables access to the target system. I use the ADS protocol even if several TwinCAT systems have to communicate with each other. There is only one problem: “Is the ADS protocol approved by the administrator on a target system?” Best Regards Oleg
Hi Oleg! Excellent suggestion. Should be noted that this only works if the remote is a Windows machine (as the ADS installation is windows binary).
Hi Jakob,
I’m working on a Windows service that allows you to write to a non-Windows target.
In my works, the use of the log is essential and therefore I make massive use of it. I use both the local disk, where Twincat resides, and remote computers, necessarily with Windows, on which I install the Twincat ADS package (see Oleg’s note).
As soon as I finish the service I share it
Giordano
Hi Giordano! I look forward to this program, will for sure find usage of it!
Hi everyone!
Just a question about these functions … is it possible to use a relative path to open a file?
We are working on different machines so I thought about using a relative path. I have tried different commands: ‘./filename.txt’ ‘filename.txt’ but it doesn’t work
I think its also possible to write the file in the network drive. The only thing to change in the function block is the AmsNetId which should be your network PC and it should be added to the route in twincat system manager. for example in my case i have tried the simple example and it works
fbFileOpen(
sNetId:=’172.18.132.101.1.1′ ,
sPathName:=’C:\Temp\hello.txt’ ,
nMode:=FOPEN_MODEAPPEND OR FOPEN_MODETEXT ,
ePath:=PATH_GENERIC ,
bExecute:= bOpen,
tTimeout:= ,
bBusy=> ,
bError=> ,
nErrId=> ,
hFile=>hFile );
fbFilePuts(
sNetId:=’172.18.132.101.1.1′ ,
hFile:=hFile ,
sLine:=’This is the first line’ ,
bExecute:=bPuts ,
tTimeout:= ,
bBusy=> ,
bError=> ,
nErrId=> );
fbFileClose(
sNetId:=’172.18.132.101.1.1′ ,
hFile:=hFile ,
bExecute:=bClose ,
tTimeout:= ,
bBusy=> ,
bError=> ,
nErrId=> );
Yes, but this assumes that the network drive is something that runs TwinCAT (or ADS). If it’s anything else (like a NAS or Linux machine) it won’t work.
Thanks Jakob, You’re the best. <3
Actually, I seem to be having an issue with the approach as presented.
Trying to figure out a solution.